使用aop类级别注释时,spring为错误的类创建代理

时间:2018-10-25 14:57:49

标签: java spring aop spring-aop

当使用带有类级别注释的spring AOP时,spring context.getBean似乎总是为每个类创建并返回代理或拦截器,无论它们是否具有注释。

此行为仅用于类级别的注释。对于方法级别的注释或执行切入点,如果不需要拦截,则getBean将返回POJO。

这是一个错误吗?如设计?还是我做错了什么?

@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 个答案:

答案 0 :(得分:1)

安迪·布朗(Andy Brown)是对的,这是设计使然。原因是根据AspectJ manual切入点指示符,例如@args@this@target@within@withincode和{{1 }}(或Spring AOP中可用子集的一部分)用于根据运行时中是否存在注释进行匹配。这就是为什么在Spring调试日志中看到为所有可能需要方面功能的组件创建了代理的原因。

如果要避免这种情况,您可以将方面重构为类似这样的形式,但代价是在建议代码中使用更难看的切入点甚至更难看的反射:

@annotation

如果bean的类或其任何方法都不带有注释,则不会创建任何代理。该建议会同时检测两种类型的注释,但如果同时存在这两种方法,则建议使用方法注释。

更新:当然,您可以在Spring内使用完整的AspectJ来代替此替代方法,而完全避免使用代理。