本文编写于 1295 天前,最后修改于 1290 天前,其中某些信息可能已经过时。
@Transactional注解的运行原理
- 首先生成事务类的动态代理对象,在执行动态代理事务类的事务方法时,会执行事务拦截器
TransactionInterceptor; 接着事务核心组件
TransactionAspectSupport开始执行事务方法主流程;- 首先调用
Connection.setAutoCommit(false)方法开启事务,本质是基于jdbc连接开启事务方法; - 接着调用目标方法
invocation.proceedWithInvocation(),依旧采用ReflectiveMethodInvocation方法调用组件调用目标方法; - 在目标方法执行完成后,判断目标方法是否发生异常;
- 如果发生异常,就调用
Connection.rollback()方法回滚事务,本质是基于jdbc连接回滚事务; - 如果没有发生异常,就调用
Connection.commit()方法提交事务,本质是基于jdbc连接提交事务;
- 首先调用
@Transactional事务动态代理对象创建过程
该创建过程和AOP的创建过程一致,只不过事务使用的是BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor来处理事务代理对象;
- 从IOC容器中获取bean;
- 调用bean后置处理器
AbstractAutoProxyCreator的postProcessBeforeInstantiation()方法; - 判断是否指定
targetSource,如果指定了targetSource会跳过bean的实例化和初始化流程,也就是会直接创建AOP代理; - 如果没有指定
targetSource,执行正常创建bean的流程,执行bean的初始化,执行initMethod方法; - 调用bean后置处理器
AbstractAutoProxyCreator的postProcessAfterInitialization()方法; - 执行
wrapIfNecessary方法包装需要被代理的bean; 获取所有的增强
advisors;- 获取xml方式配置的增强
advisors; - 此处会获取到
BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor; - 获取
@Aspect注解配置的增强advisors,调用BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors方法; - 获取IOC容器中的所有bean,判断是否添加
@Aspect注解; - 通过
@Aspect注解配置的增强advisors和事务增强的advisor合并在一起将所有的advisors返回;
- 获取xml方式配置的增强
- 调用
findAdvisorsThatCanApply方法,从所有增强的advisor中找到与当前bean相匹配的增强Advisors; 遍历当前bean中所有方法依次与
advisor的切点表达式进行匹配;- 判断目标类不是java自带的类并且不是Orderd接口类型,如果不满足该条件就不处理当前bean;
- 如果满足上面的条件,就获取
@Transactional注解中配置的属性(AbstractFallbackTransactionAttributeSource#getTransactionAttribute); - 判断目标方法是否是public方法,如果不是,则不处理当前方法;
- 判断目标方法上是否可以获取到
@Transactional事务属性,如果可以获取到,就将BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor添加到当前方法的advisors中; - 如果未从方法上获取事务属性,就尝试从类上获取
@Transactional事务属性,如果可以获取到,就将BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor添加到当前方法的advisors中;
- 创建
ProxyFactory对象,并设置相关属性; - 调用
createAopProxy方法,获取构造方法默认创建的DefaultAopProxyFactory代理工厂对象,开始选择代理方式并创建代理对象;
详细创建流程可以参考Spring AOP 动态代理的创建过程
@Transactional事务动态代理对象执行过程
- 调用事务代理对象的事务方法;
调用
AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice方法获取拦截器链chain;- 从
methodCache缓存中查找是否存在目标方法对应的拦截器链; - 如果没有从
methodCache缓存中找到对应的拦截器链,从ProxyFactory中获取目标类对应的类级别增强advisors; 依次遍历所有的增强
advsiors是否与目标方法匹配,该过程与@Transactional事务代理对象创建过程中的匹配类似;- 判断目标类不是java自带的类并且不是Orderd接口类型,如果不满足该条件就不处理当前bean;
- 如果满足上面的条件,就获取
@Transactional注解中配置的属性(AbstractFallbackTransactionAttributeSource#getTransactionAttribute); - 判断目标方法是否是public方法,如果不是,则不处理当前方法;
- 判断目标方法上是否可以获取到
@Transactional事务属性,如果可以获取到,就获取BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor中的拦截器; - 如果未从方法上获取事务属性,就尝试从类上获取
@Transactional事务属性,如果可以获取到,就获取BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor中的拦截器; - 调用
AbstractBeanFactoryPointcutAdvisor#getAdvice方法获取增强Advice,该方法会最终调用beanFactory.getBean(this.adviceBeanName, Advice.class)来获取拦截器TransactionInterceptor; - 最终将匹配的
Advisor收集到interceptorList,并放到methodCache缓存中,以便下一次从缓存获取;
- 从
- 如果拦截器链
chain为空,则通过反射调用目标方法,将结果返回; - 如果拦截器链
chain不为空,就将拦截器链chain统一封装为MethodInvocation; 调用
ReflectiveMethodInvocation#proceed,执行拦截器链;执行拦截器
TransactionInterceptor#invoke方法;- 开启事务;
- 执行目标方法;
- 判断执行目标方法后是否发生异常,如果发生异常,就回滚事务,并抛出该异常;
- 如果没有发生异常,就提交事务;
- 返回执行结果。
事务失效的常见场景
- 事务对象没有被Spring管理;
- 事务方法不是public修饰;
- 方法内部调用事务方法,这里直接内部调用,没有经过动态代理对象的增强处理,事务增强处理无法执行;
- 异常在方法内部捕获,且没有抛出;
- rollbackFor属性配置错误;
- 数据库引擎不支持事务。