问题:
我们定义一个切面类和注解
@Aspect
public class LogTrackAspect {
@Pointcut("@annotation(com.demo.aop.tLogTrackAnnotation)")
public void pointCut() {
}
@Before("pointCut()")
public void check(JoinPoint joinPoint) {
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogTrackAnnotation {
OperationType type();
}
Spring AOP在同一个类里自身方法相互调用时无法拦截。比如下面的代码:
public class Test implements TestService
{
@PivotLogTrackAnnotation(type = OperationType.ADD)
public void a() {
b();
//todo
}
@PivotLogTrackAnnotation(type = OperationType.DELETE)
public void b() {
//todo
}
}
两个方法经过AOP代理,执行时都实现系统日志记录。单独使用a方法时,没有任何问题。但使用a方法里的b方法就有问题了。a方法里调用的b方法是原始的,未经过AOP增强的。我们期望调用一次a方法会记录下两条系统日志,分别是a方法和b方法的,但实际上只能记录下a方法的日志,也就是只有一条。
原因:
在使用 Spring AOP 的时候,我们从 IOC 容器中获取的 Service Bean 对象其实都是Proxy代理对象,而不是那些 Service Bean 对象this本身,也就是说在同类Service Bean中A方法调用B,本质是 this.B(),而不是Proxy.B()故 Spring AOP 是不能拦截到这些被嵌套调用的方法的。
解决办法:
使用AopContext.currentProxy()
public class Test implements TestService {
@PivotLogTrackAnnotation(type = OperationType.ADD)
public void a() {
//b();
((Test)AopContext.currentProxy()).b();
//todo
}
@PivotLogTrackAnnotation(type = OperationType.DELETE)
public void b() {
//todo
}
}
注意:
Spring Boot需要在启动类加上以下注解
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
SSM需要xml文件配置
<aop:aspectj-autoproxy proxy-target-class="true"expose-proxy="true"/>
为什么AopContext.currentProxy()能获取到代理对象?
Spring中创建动态代理有两种方式,即jdk动态代理、cglib动态代理。
jdk动态代理创建时JdkDynamicAopProxy中的invoke方法中存入的
jdk动态代理.png
cglib动态代理CglibAopProxy在创建代理时也存入了
cglib动态代理.png
这就是为什么在同一个类中进行方法调用时嵌套aop失效用AopContext.currentProxy();能获取到代理对象的原因。
网友评论