spring creates proxy for wrong classes when using aop class level annotation

社会主义新天地 提交于 2020-05-20 23:06:42

问题


When using spring AOP with class level annotations, spring context.getBean seems to always create and return a proxy or interceptor for every class, wether they have the annotation or not.

This behavior is only for class level annotation. For method level annotations, or execution pointcuts, if there is no need for interception, getBean returns a POJO.

Is this a bug? As designed? Or am i doing something wrong?

@Component
@Aspect
public class AspectA {

    @Around("@target(myAnnotation)")
    public Object process(ProceedingJoinPoint jointPoint, MyAnnotation myAnnotation) throws Throwable {
        System.out.println(
                "AspectA: myAnnotation target:" + jointPoint.getTarget().getClass().getSimpleName());
        System.out.println(" condition:" + myAnnotation.condition());
        System.out.println(" key:" + myAnnotation.key());
        System.out.println(" value:" + myAnnotation.value());
        return jointPoint.proceed();
    }
}




@Component("myBean2")
//@MyAnnotation(value="valtest-classLevel2", key="keytest-classLevel2", condition="contest-classLevel2")
 public class MyBean2 {
     public Integer testAspectCallInt(int i){
    System.out.println("MyBean2.testAspectCallInt(i=" + i + ")");
    return i+1000;
    }
}








@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MyAnnotation {
  String value()      default "";
  String key()         default "";
  String condition() default "";
}


@ComponentScan()
@EnableAspectJAutoProxy
public class Test {
      public static void main(String[] args) {
          ApplicationContext ctx =  new AnnotationConfigApplicationContext(Test.class);

          MyBean2 bean   = (MyBean2)ctx.getBean("myBean2");
          System.out.println(bean.getClass());  // prints CGLIB proxy, even when annotation is commented out on class

          bean.testAspectCallInt(12); // calling method
      }
    }

回答1:


Andy Brown is right, it is by design. The reason is that according to the AspectJ manual pointcut designators such as @args, @this, @target, @within, @withincode, and @annotation (or the subset of those available in Spring AOP) are used to match based on the presence of an annotation at runtime. This is why in the Spring debug log you see that proxies are created for all components which might need aspect functionality.

If you want to avoid that, you can refactor your aspect into something like this at the cost of an uglier pointcut and even uglier reflection in the advice code:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;

@Component
@Aspect
public class AspectA {
  @Around("execution(* (@MyAnnotation *).*(..)) || execution(@MyAnnotation * *(..))")
  public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
    MyAnnotation myAnnotation = null;
    for (Annotation annotation : ((MethodSignature) joinPoint.getSignature()).getMethod().getDeclaredAnnotations()) {
      if (annotation instanceof MyAnnotation) {
        myAnnotation = (MyAnnotation) annotation;
        break;
      }
    }
    if (myAnnotation == null) {
      myAnnotation = joinPoint.getTarget().getClass().getAnnotationsByType(MyAnnotation.class)[0];
    }
    System.out.println("AspectA: myAnnotation target:" + joinPoint.getTarget().getClass().getSimpleName());
    System.out.println(" condition:" + myAnnotation.condition());
    System.out.println(" key:" + myAnnotation.key());
    System.out.println(" value:" + myAnnotation.value());
    return joinPoint.proceed();
  }
}

If neither the bean's class nor any of its methods bears the annotation, no proxy will be created. The advice detects both types of annotation, but prefers a method annotation if both are present.

Update: Instead of this workaround you could of course use full AspectJ from within Spring and avoid proxies altogether.



来源:https://stackoverflow.com/questions/52992365/spring-creates-proxy-for-wrong-classes-when-using-aop-class-level-annotation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!