美文网首页编程实战
Spring AOP嵌套调用的问题

Spring AOP嵌套调用的问题

作者: Neil_Wong | 来源:发表于2021-08-31 19:08 被阅读0次

    问题:

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

    @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();能获取到代理对象的原因。

    相关文章

      网友评论

        本文标题:Spring AOP嵌套调用的问题

        本文链接:https://www.haomeiwen.com/subject/wwgziltx.html