如何解决spring AOP中自身方法调用无法应用代理的问题

这篇文章主要介绍如何解决spring AOP中自身方法调用无法应用代理的问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

    spring AOP中自身方法调用无法应用代理

    如下例

    public class MyServiceImpl implements MyService {
     public void do(){
      //the transaction annotation won't work if you directly invoke handle() method with 'this'
      this.handle();
     }
     @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
     public void handle() {
      //sth with transaction
     }
    }

    如果直接调用this的handle()方法则事务无法生效,原因是spring的AOP是通过代理实现的,像这样直接调用本对象的方法是不会应用代理的。

    可以使用如下两种方式修改代码以应用事务

    (1)在MyServiceImpl中声明一个MyService对象
    public class MyServiceImpl implements MyService {
     @Autowired
     private MyService myService;
     
     public void do(){
      //use myService object
      myService.handle();
     }
     @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
     public void handle() {
      //sth. with transaction
     }
    }
    (2)使用AopContext类
    public class MyServiceImpl implements MyService {
     public void do(){
      //fetch current proxy objet from AopContext
      ((MyService)AopContext.currentProxy()).handle();
     }
     @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
     public void handle() {
      //sth with transaction
     }
    }

    注意,原生的AspectJ是不会有这种自身调用的问题的,因为它不是基于代理的AOP框架。

    spring aop 内部方法调用事务不生效

    方法1:

    基于 proxy 的 spring aop 带来的内部调用问题可以使用 AopContext.currentProxy() 强转为当前的再调用就可以解决了

    例如:

    错误用法:

    public Account getAccountByName2(String userName) {
      return this.getAccountByName(userName);
    }

    修改为:

    public Account getAccountByName2(String userName) {
      return ((AccountService)AopContext.currentProxy()).getAccountByName(userName);
    }

    另外注意:要设置aop实体暴露出来。在springboot的application.java里面加上

    @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

    方法2:

    利用初始化方法在目标对象中注入代理对象

    在目标对象类中注入spring上下文,通过context获取代理对象,并调用代理对象的方法。

    注意:该方案对于scope为prototype的bean无法适用,因为每次获取bean时都返回一个新的对象。

    方法2.1:

    //延迟加载方式
    private TestService testService;
    @Autowired
    @Lazy
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    方法2.2:

    import javax.annotation.PostConstruct;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Service;
    import com.blog.common.aop.service.TestService;
    @Service
    public class TestServiceImpl implements TestService {
        @Autowired
        private ApplicationContext context;
        private TestService proxyObject;
        @PostConstruct
        // 初始化方法,在IOC注入完成后会执行该方法
        private void setSelf() {
            // 从spring上下文获取代理对象(直接通过proxyObject=this是不对的,this是目标对象)
            // 此种方法不适合于prototype Bean,因为每次getBean返回一个新的Bean
            proxyObject = context.getBean(TestService.class);
        }
        public void methodA() throws Exception {
            System.out.println("method A run");
            System.out.println("method A 中调用method B,通过注入的代理对象,调用代理对象的方法,解决内部调用实现的问题。");
            proxyObject.methodB(); //调用代理对象的方法,解决内部调用失效的问题
        }
        public void methodB() {
            System.out.println("method B run");
        }
    }

    以上是“如何解决spring AOP中自身方法调用无法应用代理的问题”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!