问题描述
最近有个需求,统计某个方法的调用次数,开始使用 Spring AOP 实现,后来发现当方法被内部调用时,切面逻辑将不会生效,直接上样例:
定义接口,包含方法 A,方法 B
public interface ISon {
void A();
void B();
}
定义接口实现,方法 B 调用方法 A
@Service
public class Son implements ISon {
@Override
public void A() {
System.out.println("method A");
}
@Override
public void B() {
System.out.println("method B");
A();
}
}
切点定义,对方法 A 进行增强
@Aspect
@Component
public class AspectDemo {
@Pointcut(value = "execution(* com.example.transactiondemo.aop.ISon.A(..))")
public void pointCut(){
}
@Before("pointCut()")
public void before(JoinPoint joinPoint){
System.out.println("before ");
}
@After("pointCut()")
public void after(){
System.out.println("after ");
}
}
测试
@Autowired
private ISon iSon;
@Test
public void test11(){
iSon.A();
System.out.println("-----------");
iSon.B();
}
打印输出
before
method A
after
-----------
method B
method A
可以发现,如果直接使用 实例调用 A,会进行增强;但是如果是方法 B 调用,A 的增强逻辑将失效。
失效原因
方法 A 被调用,是基于 AOP 生成的 代理对象 进行的调用;方法 B 调用方法 A ,是 this 目标对象 直接调用,并不是代理对象进行调用
解决方案
回到最开始的需求,如何通过切面的方式获取某一个方法的调用次数? 包括方法自调用
-
使用 AopContext.currentProxy()
切面开启注解
@EnableAspectJAutoProxy(exposeProxy = true,proxyTargetClass = true)
方法 B 不直接调用 A
@Override public void B() { System.out.println("method B"); ((Son) AopContext.currentProxy()).A(); }
-
先获取上下文的 Bean 再调用
@Autowired private ApplicationContext applicationContext; ((Son) applicationContext.getBean(Son.class)).A();