Spring AOP嵌套调用的问题

问题:

我们定义一个切面类和注解

@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文件配置


为什么AopContext.currentProxy()能获取到代理对象?

Spring中创建动态代理有两种方式,即jdk动态代理、cglib动态代理。
jdk动态代理创建时JdkDynamicAopProxy中的invoke方法中存入的


jdk动态代理.png

cglib动态代理CglibAopProxy在创建代理时也存入了


cglib动态代理.png

这就是为什么在同一个类中进行方法调用时嵌套aop失效用AopContext.currentProxy();能获取到代理对象的原因。

你可能感兴趣的:(Spring AOP嵌套调用的问题)