spring动态代理失效,AOP失效,事务@Transactional失效原因

事务基于@Transactional注解和AOP(动态代理)

1. 动态代理失效

对于基于接口动态代理的 AOP 事务增强来说,由于接口的方法都必然是 public 的,这就要求实现类的实现方法也必须是 public 的(不能是 protected、private 等),同时不能使用 static 的修饰符。所以,可以实施接口动态代理的方法只能是使用 public 或 public final 修饰符的方法,其他方法不可能被动态代理,相应的也就不能实施 AOP 增强,换句话说,即不能进行 Spring 事务增强了。

基于 CGLib 字节码动态代理的方案是通过扩展被增强类,动态创建其子类的方式进行 AOP 增强植入的。由于使用 final、static、private 修饰符的方法都不能被子类覆盖,相应的,这些方法将无法实施 AOP 增强。所以方法签名必须特别注意这些修饰符的使用,以免使方法不小心成为事务管理的漏网之鱼。

2. AOP失效

第一种(要增强的类或方法没被spring管理)

对于传统的web项目来说,通常使用spring和springmvc,因此对于这种项目来讲,他是有两个容器的,一个是spring容器,一般我们会把Service层的东西注入到spring容器中,另一个是springmvc的容器,通常这个容器里注入的是Controller层的东西,这里我们认为spring容器是父容器,springmvc是子容器的概念,然后我们大家都知道通过父子继承关系可知,子容器是可以读取到父容器中的东西,但是父容器是无法读到子容器中的内容,因此基于这个场景,有的同学,把Aop的实现类注入到了spring容器中,并且将Aop的切点表达式配置aop:config <aop:pointcut的execution也配到了spring容器的xml,而巧了这位同学要切的类方法,正好是Controller,也就是springmvc容器中的东西,那么这时候问题就来了,aop在初始化时会在自己的容器中寻找能够匹配的类方法,然后给他套上一层代理,此时他在自己能够访问到的spring容器中根本找不到与之匹配的类和方法,因为这些类和方法是在springmvc容器中管理的,因此就没有代理成功

解决:那么对于上述问题要怎么修改呢?只需要确保你要Aop切的类和方法与你Aop配置切点aop:config <aop:pointcut的execution表达式声明是在同一个容器中即可,此时只需要将这个配置移到springmvc容器的xml中即可

第二种(要被增强的类或方法同时被spring和springMVC扫描)

第二种情况与第一种情况有些许的类似,但并不相同,是关于重复扫描的,比如你在spring容器中配置了一个Aop,并且把他托管给spring容器管理,而且execution表达式切的也是spring容器中管理的类和方法,理论上这个时候是好用的,这批execution切到的类都被加了代理,但是巧了,springmvc容器中由于配置的是包路径扫描,恰好把execution表达式切的这一批对象又扫了一遍,又都托管给了springmvc容器,而此时扫到的这批对象,是重新new出来交给springmvc管理的,因此并没有被aop代理,所以在使用时,注入进来的可能是springmvc容器管理的这批对象,因此使用时发现Aop代理失效了

解决:这个问题的解决方案,就是避免两个容器重复扫描。

第三种(要增强的方法被同类的方法调用)

第三个问题就比较简单了,他的现象是有些方法被Aop代理成功了,但有个别方法没有代理成功,究其原因发现这部分没有代理成功的方法并不是通过代理对象调用的,而是自身调用的,故被调用的方法没有被Aop代理,无法织入横切逻辑。

解决:举个栗子,比如A.a(),A.b()是被代理的类和方法,那么当我调用A.a()时,此时a被代理了,成功执行代理类的内容,但还没有完,a()方法中调用了自身的方法b(),此时我们以为b也会被代理类代理,但实际上并没有,因为他是自身方法调用了并不是通过代理类A调用的,在a方法中可以通过((A) AopContext.currentProxy()).b()调用,不过前提是配置上<aop:config expose-proxy="true">,expose-proxy="true"是重点(先开启cglib代理,开启 exposeProxy = true,暴露代理对象)

第四种(用的注解方式没有开启注解支持)

这种就更好理解了,只需要开启注解支持就行了。

xml方式开启在spring配置文件添加上aop:aspectj-autoproxy/即可

注解方式开启在启动类上添加@EnableAspectJAutoProxy即可

总结

第一种和第二种是因为MVC分层没有用好,接收数据和业务逻辑要分开,

第三种是因为代理模式限制

第四种就是使用不当了

3. @Transactional失效

事务基于注解和AOP,注解失效和AOP失效

原因一:没有开启事务管理

原因二:标注了@Transactional的方法里面的异常被捕获了

原因三:标注了@Transactional的方法发生了非Error 或者 非RuntimeException

原因四:标注了@Transactional的方法的事务传播类型propagation配置成了NOTSUPPORT

原因五:标注了@Transactional的方法的事务传播类型propagation配置成了NEVER

原因六:标注了@Transactional的方法的事务传播类型propagation配置成了SUPPORTS且当前没有事务

原因七:外部调用方法A,A内部调用方法B,A没有@Transaction注解而B有@Transactional注解

原因九:标注了@Transactional的方法不是public的

原因十:标注了@Transactional的方法发生的异常不是rollbackFor指定的类型或子类

原因十一:数据库不支持事务

相关推荐
马剑威(威哥爱编程)2 分钟前
2025春招 SpringCloud 面试题汇总
后端·spring·spring cloud
硬件人某某某8 分钟前
Java基于SSM框架的社区团购系统小程序设计与实现(附源码,文档,部署)
java·开发语言·社区团购小程序·团购小程序·java社区团购小程序
程序员徐师兄9 分钟前
Java 基于 SpringBoot 的校园外卖点餐平台微信小程序(附源码,部署,文档)
java·spring boot·微信小程序·校园外卖点餐·外卖点餐小程序·校园外卖点餐小程序
chengpei14726 分钟前
chrome游览器JSON Formatter插件无效问题排查,FastJsonHttpMessageConverter导致Content-Type返回不正确
java·前端·chrome·spring boot·json
Quantum&Coder26 分钟前
Objective-C语言的计算机基础
开发语言·后端·golang
五味香27 分钟前
Java学习,List 元素替换
android·java·开发语言·python·学习·golang·kotlin
Joeysoda31 分钟前
Java数据结构 (从0构建链表(LinkedList))
java·linux·开发语言·数据结构·windows·链表·1024程序员节
扫地僧00933 分钟前
(Java版本)基于JAVA的网络通讯系统设计与实现-毕业设计
java·开发语言
天乐敲代码34 分钟前
JAVASE入门九脚-集合框架ArrayList,LinkedList,HashSet,TreeSet,迭代
java·开发语言·算法
endcy20161 小时前
IoTDB结合Mybatis使用示例(增删查改自定义sql等)
java·mybatis·iotdb