同一个类调方法导致注解式事务失效的问题

说明

在项目启动时,如果有@Transactional注解,spring是生成代理类来开启事务、提交事务和回滚事务的,但是如果是同一个类之间调用,就是直接调方法,导致事务失效。我们可以用一下方式在同一类获取当前类的代理对象,从而避免事务失效的问题。但是这种方式会有问题,下面有说明。推荐调用拆到两个类中

代码

  • 在启动类开启
@EnableAspectJAutoProxy(exposeProxy = true)
  • 使用
    handle()上有@Transactional事务注解
AService aService = (AService ) AopContext.currentProxy();
WebResult webResult = aService.handle();

使用上述方法需要注意的点

  • 需要确保当前方法是通过代理对象调用的,而不是直接通过类的实例调用的。否则,AopContext.currentProxy()将返回null。
  • 需要在Spring容器中开启了exposeProxy配置,即在@EnableAspectJAutoProxy注解中设置exposeProxy属性为true。否则,AopContext.currentProxy()将返回null。
  • 需要注意潜在的性能影响。每次调用AopContext.currentProxy()都会涉及到AOP拦截器链的处理,可能会对性能产生一定的影响。因此,建议在必要的情况下使用,并进行性能测试和评估。

总之,使用AopContext.currentProxy()可以解决同一个类调用方法导致注解式事务失效的问题,但需要注意上述提到的使用条件和潜在的性能影响及可能会破坏Spring AOP的默认行为。

破坏的Spring AOP的默认行为

破坏Spring AOP的默认行为主要包含以下几种方式:

  1. 强制使用CGLIB代理:在Spring AOP中,默认情况下,如果被代理的对象没有实现接口,会使用CGLIB来创建代理对象。但是,如果你强制使用CGLIB代理,即使被代理的对象已经实现了接口,也会使用CGLIB来创建代理对象,破坏了Spring AOP的默认行为。
  2. 修改默认的代理实现方式:在Spring Boot 2.x中,AOP默认使用CGLIB实现,而在Spring 5.x中,AOP默认使用JDK动态代理。如果你通过配置项spring.aop.proxy-target-class=false来修改默认的代理实现方式,即使是在Spring Boot 2.x中,也会使用JDK动态代理来创建代理对象,破坏了Spring AOP的默认行为。
  3. 使用AspectJ织入:Spring AOP默认使用基于代理的AOP实现,即Spring会创建一个代理对象,然后将该代理对象织入到目标对象中。如果你使用AspectJ织入,Spring会创建一个Aspect对象,然后将该Aspect对象织入到目标对象中,破坏了Spring AOP的默认行为。

需要注意的是,这些行为并不一定都是负面的。它们有可能帮助解决某些特定的问题。但是,在破坏Spring AOP默认行为之前,一定要考虑清楚是否真的需要这样做,以及可能的副作用是什么。

posted @ 2023-09-22 15:08  品书读茶  阅读(163)  评论(0编辑  收藏  举报