具有带注释参数的切入点匹配方法

时间:2010-08-25 12:20:20

标签: java parameters annotations aop aspectj

如果符合以下情况,我需要使用与方法匹配的切入点创建方面:

  1. 使用MyAnnotationForMethod
  2. 进行注释
  3. 其中一个参数(可以有很多)用@MyAnnotationForParam注释(但也可以有其他注释)。
  4. 方面类看起来像这样

    @Pointcut("execution(@MyAnnotationForMethod * *(..,@aspects.MyAnnotationForParam Object, ..)) && args(obj)")
    void myPointcut(JoinPoint thisJoinPoint, Object obj) {
    }
    
    @Before("myPointcut(thisJoinPoint ,  obj)")
    public void doStuffOnParam(JoinPoint thisJoinPoint, Object obj) {
        LOGGER.info("doStuffOnParam :"+obj);
    }
    

    带注释的方法

    @MyAnnotationForMethod
    public string theMethod(String a, @MyAnnotationForParam @OtherAnnotation Object obj, Object b){ 
        LOGGER.info(a+obj+b);
    }
    

    使用eclipse - >警告:关于poincut:

    Multiple markers at this line 
        - no match for this type name: MyAnnotationForMethod [Xlint:invalidAbsoluteTypeName] 
        - no match for this type name: aspects.MyAnnotationForParam On the before : advice defined in xxx.xxx.xxx.xxx.MyAspect has not been applied [Xlint:adviceDidNotMatch]
    

    使用http://download.eclipse.org/tools/ajdt/35/update

    中的last aspectJ插件

    使用aspectj 1.6.9的maven命令行

    [WARNING] no match for this type name: MyAnnotationForMethod [Xlint:invalidAbsoluteTypeName]
    [WARNING] no match for this type name: aspects.MyAnnotationForParam [Xlint:invalidAbsoluteTypeName]
    [WARNING] advice defined in xxx.xxx.xxx.xxx.MyAspect has not been applied [Xlint:adviceDidNotMatch]
    

    注释:

    package com.xxx.xxx.annotation;
    // standard imports stripped
    @Documented
    @Target( { FIELD, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    public @interface @MyAnnotationForParam {}
    

    package com.xxx.xxx.annotation;
    // standard imports stripped
    @Target(METHOD)
    @Retention(RUNTIME)
    @Documented
    public @interface MyAnnotationForMethod {}
    

    当然它没有正常运作。

    你能告诉我出了什么问题吗?

    THX。

2 个答案:

答案 0 :(得分:11)

<强>更新

好的,我能找到的最佳参考是在这个页面上:Annotations, Pointcuts and Advice

您可以匹配该方法,但是您将无法捕获参数(只是方法和注释)。所以你需要做的是切入点匹配和反射的组合。像这样:

@Pointcut(
    "execution(@com.xxx.xxx.annotation.MyAnnotationForMethod * *(.., @com.xxx.xxx.annotation.MyAnnotationForParam (*), ..))")
public void annotatedMethod(){}

@Before("annotatedMethod()")
public void doStuffOnParam(final JoinPoint jp){
    final Signature signature = jp.getSignature();
    if(signature instanceof MethodSignature){
        final MethodSignature ms = (MethodSignature) signature;

        final Method method = ms.getMethod();
        final String[] parameterNames = ms.getParameterNames();
        final Class<?>[] parameterTypes = ms.getParameterTypes();
        final Annotation[][] parameterAnnotations =
            method.getParameterAnnotations();
        for(int i = 0; i < parameterAnnotations.length; i++){
            final Annotation[] annotations = parameterAnnotations[i];
            final MyAnnotationForParam paramAnnotation =
                getAnnotationByType(annotations, MyAnnotationForParam.class);
            if(paramAnnotation != null){
                this.processParameter(ms.toShortString(),
                    parameterNames[i],
                    parameterTypes[i],
                    paramAnnotation);
            }

        }
    }
}

/**
 * In an array of annotations, find the annotation of the specified type, if any.
 * @return the annotation if available, or null
 */
@SuppressWarnings("unchecked")
private static <T extends Annotation> T getAnnotationByType(final Annotation[] annotations,
    final Class<T> clazz){

    T result = null;
    for(final Annotation annotation : annotations){
        if(clazz.isAssignableFrom(annotation.getClass())){
            result = (T) annotation;
            break;
        }
    }
    return result;
}

/**
 * Do some processing based on what we found.
 * @param signature method signature
 * @param paramName parameter name
 * @param paramType parameter type
 * @param paramAnnotation annotation we found
 */
private void processParameter(final String signature,
    final String paramName,
    final Class<?> paramType,
    final MyAnnotationForParam paramAnnotation){

    System.out.println(MessageFormat.format(
        "Found parameter ''{0}'' \n  of type ''{1}'' \n  with annotation ''{2}'' \n  in method ''{3}''",
        paramName,
        paramType,
        paramAnnotation,
        signature));
}

以下是我上述方面的测试类:

public class TestClass{

    @MyAnnotationForMethod
    public void simpleTestMethod(@MyAnnotationForParam final String param1){
        System.out.println("Method body (simple)");
    };

    @MyAnnotationForMethod
    public void complexTestMethod(final String param1,
        @MyAnnotationForParam final Float param2,
        @MyAnnotationForParam final Boolean param3){
        System.out.println("Method body (complex)");
    };

    public static void main(final String[] args){
        System.out.println("Starting up");
        final TestClass testObject = new TestClass();
        testObject.simpleTestMethod("Hey");
        testObject.complexTestMethod("Hey", 123.4f, false);
        System.out.println("Finished");
    }

}

这是输出:

Starting up
Found parameter 'param1' 
  of type 'class java.lang.String' 
  with annotation '@com.xxx.xxx.annotation.MyAnnotationForParam()' 
  in method 'TestClass.simpleTestMethod(..)'
Method body (simple)
Found parameter 'param2' 
  of type 'class java.lang.Float' 
  with annotation '@com.xxx.xxx.annotation.MyAnnotationForParam()' 
  in method 'TestClass.complexTestMethod(..)'
Found parameter 'param3' 
  of type 'class java.lang.Boolean' 
  with annotation '@com.xxx.xxx.annotation.MyAnnotationForParam()' 
  in method 'TestClass.complexTestMethod(..)'
Method body (complex)
Finished

提示

您可能希望缓存大量此操作,无需在每次执行中解析每个注释的每个参数。保留哪个方法的哪个参数带有注释的地图,并仅处理这些参数。

答案 1 :(得分:1)

当从接口实现该方法时,上述解决方案中的ms.getParameterNames()调用似乎不起作用。我找回了空位。

但是,如果我启用CGLIB,那么它可以工作。

<aop:aspectj-autoproxy proxy-target-class="true"/>