当从匿名类'方法调用方法时,为什么不能执行aop?

时间:2013-10-18 00:52:10

标签: java aspectj anonymous-inner-class

以下是我的自定义注释AnnoLogExecTime和类AOP

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnnoLogExecTime {

}

@Aspect
@Service
public class AOP {
    Logger logger = LoggerFactory.getLogger(AOP.class);

    @Around("execution(@com.judking.general.aop.AnnoLogExecTime * *(..))")
    public Object calExecTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable        {
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = signature.getMethod();

        long t1 = System.currentTimeMillis();
        Object obj = proceedingJoinPoint.proceed();
        long t2 = System.currentTimeMillis();

        logger.info("method `"+method.getName()+"` takes "+(t2-t1)+"ms");
        return obj;
    }
}

测试用例如下:

@Service
class A    {
  public void go()  {
    B b = new B()  {    //Anonymous class B
      @Override
      public void exec()    {
        aopMethod();
      }
    };
    b.exec();
  }

  @AnnoLogExecTime
  public void aopMethod()    {
    System.out.println("aopMethod");
  }
}

@Service
class B    {
  public void exec()    {
    System.out.println("exec");
  }
}

当我致电a.aopMethod()时,AOP.calExecTime已联系到a.aopMethod()

但是如果我拨打a.go(),使用匿名班B个实例来呼叫a.aopMethod(),那么AOP.calExecTime 就会联系起来到a.aopMethod()

有人能解释一下这种现象吗?请给我一个方法来解决匿名类的问题。非常感谢!

1 个答案:

答案 0 :(得分:1)

这并不完全是因为它是一个匿名的内部类。 您遇到的是AOP代理的限制。

当你有

A a = ...; // get proxy

代理本身将实际实例包装在包装器实例中。通过调用

与此包装器实例进行交互时
a.aopMethod();

代理拦截器拦截调用并可以执行建议。

这适用于您致电

a.go()

如果有连接点。相反,没有任何内容拦截该调用,并且对go()的调用将通过拦截器并在实际实例上调用该方法

actualA.go();

创建匿名内部类并具有

@Override
public void exec()    {
    aopMethod();
}

隐含地做了

@Override
public void exec()    {
    A.this.aopMethod();
}

围绕代理,因为你在实际的实例上调用它,而不是包装器。

您可能没有使用Spring来生成代理,但是their documentation explains this pretty well.