2015-04-16 61 views
5

我在創建切入點時會遇到一些問題,該切入點將對具有特定註釋參數的bean進行操作。我最終的目標是驗證參數在處理之前的值,但目前我只需要創建切入點。如何基於註釋參數編寫切面切入點

考慮下面的註釋

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.PARAMETER }) 
public @interface MyAnnotation {} 

我再像這個應用到了一些類似的方法:

public void method1(@MyAnnotation long i) {} 
public void method2(String someThing, @MyAnnotation long i) {} 
public void method3(String someThing, @MyAnnotation long i, byte value) {} 

所以

  • 我都不在乎類(或包)的方法在
  • 註釋的位置編者的論點會有所不同
  • 我知道註釋值僅適用於特定類型的

我的切入點執行工作必須東西沿着線:

@Before(value = "* *(..) && args(verifyMe)") 
public void verifyInvestigationId(long verifyMe) {} 

我變得有點困惑關於價值究竟是什麼以及如何配合註釋及其類型。在這一點上,它可能不值得列出我試過的東西!

更新:根據我在http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170見過的意見(和糾正一對夫婦誤解和增加空間我忽略了)我必須在以下工作點:

@Before("execution(public * *(.., @full.path.to.MyAnnotation (*), ..))") 
public void beforeMethod(JoinPoint joinPoint) { 
    System.out.println("At least one of the parameters are annotated with @MyAnnotation"); 
} 

這幾乎是我所需要的 - 所有我需要做的是通過註釋的參數的值作爲參數方法。我不能完全弄清楚讓Spring做這件事的語法(鏈接的答案沒有顯示這一點)。

+0

可能重複http://stackoverflow.com/questions/2766844/pointcut-matching-methods-with-annotated-parameters) – sheltem

+0

@sheltem,感謝您指出這一點。不幸的是,這是我嘗試過的一件事,但失敗了。日誌包含以下錯誤:切入點格式不正確:期望字符位置處的'名稱模式'執行(公共* *(..,@ aspects.VerifyMe(*),..)) – Stormcloud

+0

BTW:有兩個「公共」一詞後,由一個空格隔開的單詞 - stackoverflow將它們解釋爲斜體! – Stormcloud

回答

5

非常相似,my answer heresheltem已經指出,該解決方案看起來像這樣(在註釋風格的語法這個時間,因爲在Spring AOP不能使用本地AspectJ的語法):

樓主的註釋:

package annotations; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.PARAMETER }) 
public @interface MyAnnotation {} 

驅動器應用:

我使用驅動程序應用程序來測試我的AspectJ解決方案。在Spring中,類和方面都需要成爲Spring bean /組件才能實現。

package de.scrum_master.app; 

import java.util.ArrayList; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Set; 

import annotations.MyAnnotation; 

public class Application { 
    public void method1(@MyAnnotation int i) {} 
    public void method2(String id, @MyAnnotation float f) {} 
    public void method3(int i, @MyAnnotation List<String> strings, @MyAnnotation String s) {} 
    public void method4(int i, @MyAnnotation Set<Integer> numbers, float f, boolean b) {} 
    public void method5(boolean b, String s, @MyAnnotation String s2, float f, int i) {} 
    public void notIntercepted(boolean b, String s, String s2, float f, int i) {} 

    public static void main(String[] args) { 
     List<String> strings = new ArrayList<String>(); 
     strings.add("foo"); 
     strings.add("bar"); 
     Set<Integer> numbers = new HashSet<Integer>(); 
     numbers.add(11); 
     numbers.add(22); 
     numbers.add(33); 

     Application app = new Application(); 
     app.method1(1); 
     app.method2("foo", 1f); 
     app.method3(1, strings, "foo"); 
     app.method4(1, numbers, 1f, true); 
     app.method5(false, "foo", "bar", 1f, 1); 
     app.notIntercepted(false, "foo", "bar", 1f, 1); 
    } 
} 

看點:

package de.scrum_master.aspect; 

import java.lang.annotation.Annotation; 

import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.SoftException; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
import org.aspectj.lang.reflect.MethodSignature; 

import annotations.MyAnnotation; 

@Aspect 
public class ArgCatcherAspect { 
    @Before("execution(public * *(.., @MyAnnotation (*), ..))") 
    public void interceptMethodsWithAnnotatedParameters(JoinPoint thisJoinPoint) { 
     System.out.println(thisJoinPoint); 
     MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature(); 
     String methodName = signature.getMethod().getName(); 
     Class<?>[] parameterTypes = signature.getMethod().getParameterTypes(); 
     Annotation[][] annotations; 
     try { 
      annotations = thisJoinPoint.getTarget().getClass(). 
       getMethod(methodName, parameterTypes).getParameterAnnotations(); 
     } catch (Exception e) { 
      throw new SoftException(e); 
     } 
     int i = 0; 
     for (Object arg : thisJoinPoint.getArgs()) { 
      for (Annotation annotation : annotations[i]) { 
       if (annotation.annotationType() == MyAnnotation.class) 
        System.out.println(" " + annotation + " -> " + arg); 
        // Verify 'arg' here or do whatever 
      } 
      i++; 
     } 
    } 
} 

控制檯日誌:

execution(void de.scrum_master.app.Application.method1(int)) 
    @annotations.MyAnnotation() -> 1 
execution(void de.scrum_master.app.Application.method2(String, float)) 
    @annotations.MyAnnotation() -> 1.0 
execution(void de.scrum_master.app.Application.method3(int, List, String)) 
    @annotations.MyAnnotation() -> [foo, bar] 
    @annotations.MyAnnotation() -> foo 
execution(void de.scrum_master.app.Application.method4(int, Set, float, boolean)) 
    @annotations.MyAnnotation() -> [33, 22, 11] 
execution(void de.scrum_master.app.Application.method5(boolean, String, String, float, int)) 
    @annotations.MyAnnotation() -> bar 
[帶有加註解的參數匹配的切入點方法](的
+0

非常全面,很好的答案。謝謝! –

0

這是我結束了在擺弄它(進口略)後:

@Aspect 
public class VerifyAspect { 

    @Before("execution(* *(.., @annotations.MyAnnotation (*), ..)) && args(.., verifyMe)") 
    public void verifyInvestigationId(final Object verifyMe) { 
     System.out.println("Aspect verifying: " + verifyMe); 
    } 
} 

無需特定的春天什麼,如果需要的話作爲AspectJ的已經爲您提供了參數。

+0

不錯(當然,它更接近於我設法使用的任何東西!),但是它有一個限制,即作爲「verifyMe」傳遞的參數始終是傳遞給分割點方法的實際參數。 有沒有辦法按照「用指定的註釋向我發送參數」的說法? – Stormcloud

+0

你是對的,這可能不會在每種情況下給你註釋參數。嗯...回到畫板! – sheltem

+0

雖然作爲臨時解決方案,但您可以讓AspectJ爲您提供JoinPoint並通過反射遍歷其參數,以找到那些註釋符註釋的參數。不是很優雅,但應該開始工作。 – sheltem

相關問題