以下是我的自定义注释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()
。
有人能解释一下这种现象吗?请给我一个方法来解决匿名类的问题。非常感谢!
答案 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.