@EnableTransactionManagement import了TransactionManagementConfigurationSelector,而TransactionManagementConfigurationSelector继承于AdviceModeImportSelector根据@EnableTransactionManagement配置的AdviceMode引入不同的类。

我们只看proxy模式下引入的AutoProxyRegistrar和ProxyTransactionManagementConfiguration。

AutoProxyRegistrar——引入aop代理

AutoProxyRegistrar继承于ImportBeanDefinitionRegistrar,注册定义用于aop代理生成的InfrastructureAdvisorAutoProxyCreator的BeanDefinition

ProxyTransactionManagementConfiguration——生成事务相关类

  1. TransactionalEventListenerFactory:其父类AbstractTransactionManagementConfiguration生成一个TransactionalEventListenerFactory用于创建ApplicationListenerMethodTransactionalAdapter,向TransactionSynchronizationManager注册@TransactionalEventListener注解的方法生成的TransactionSynchronization。
  2. TransactionAttributeSource:用于解析事务注解,包括Spring的@Transactional、jta的@Transactional、ejb3的@TransactionAttribute注解
  3. TransactionInterceptor:事务通知Advice,完成事务的主要逻辑,底层将获取事务、回滚、提交委托给TransactionManager
  4. BeanFactoryTransactionAttributeSourceAdvisor:事务切面通知Advisor,通过TransactionAttributeSource判断方法是否包含事务注解,通过TransactionInterceptor完成事务通知。

TransactionInterceptor

TransactionInterceptor主要逻辑位于父类TransactionAspectSupport的invokeWithinTransaction方法

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
//1.通过TransactionAttributeSource解析事务注解获取TransactionAttribute,来决定使用何种TransactionManager
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr); if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
//tm为ReactiveTransactionManager类型,即响应式的事务管理器逻辑,这里省略。。。
} PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
//2.创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
//3.执行后续通知和执行代码
Object retVal;
try {
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 4.抛错异常判断是否回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 5.重置线程绑定的TransactionInfo
cleanupTransactionInfo(txInfo);
} //省略部分无关代码。。。。 //6.提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
} else {
//tm为CallbackPreferringPlatformTransactionManager类型,即异步回调的事务管理器,使用execute处理事务,这里省略。。。
}
}

1. 根据事务注解决定TransactionManager

protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
//获取注解配置的TransactionManager,例如@Transactional("dataSourceTransactionManager")
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
//获取TransactionInterceptor配置的默认transactionManagerBeanName
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
//获取TransactionInterceptor配置的默认transactionManager
TransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
//获取beanFactory中TransactionManager类型的bean
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}

2. 创建事务

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) { //省略代码。。。 //通过PlatformTransactionManager开启事务
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
}
//封装TransactionInfo,并绑定到线程上(即存储在Threadlocal中)
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

3. 执行后续通知和代码

4. 抛错异常判断是否回滚

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
//1.事务注解上回滚的异常规则与当前异常匹配,执行回滚,即@Transactional(rollbackFor = Exception.class),ex instanceof Exception
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
//省略异常处理(日志和抛错)。。。。
catch (TransactionSystemException ex2) {
}
catch (RuntimeException | Error ex2) {
}
}
//1.事务注解上回滚的异常规则与当前异常不匹配,执行提交,但TransactionStatus.isRollbackOnly()为true也会进行回滚
else {
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
//省略异常处理(日志和抛错)。。。。
catch (TransactionSystemException ex2) {
}
catch (RuntimeException | Error ex2) {
}
}
}
}

5. 重置线程绑定的TransactionInfo

protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
//重置为原来的TransactionInfo
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}

6. 无异常提交事务

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}

spring tx——@EnableTransactionManagement的更多相关文章

  1. 学习Spring5必知必会(7)~Spring tx

    一.spring的事务管理 1.引出事务的经典例子:银行转账发生异常 ✿ 解决:把转出钱和转入钱的业务放到同一个事务空间. ■ 分析转账过程流程: ① 首先,获取 DataSource 对象: ② 其 ...

  2. spring tx:advice 和 aop:config 配置事务

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  3. Spring -- <tx:annotation-driven>注解基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)的区别。

    借鉴:http://jinnianshilongnian.iteye.com/blog/1508018 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional ...

  4. Spring <tx:annotation-driven>注解 JDK动态代理和CGLIB动态代理 区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

  5. [转]spring tx:advice 和 aop:config 配置事务

      <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www. ...

  6. spring 事务 @EnableTransactionManagement原理

    @EnableXXX原理:注解上有个XXXRegistrar,或通过XXXSelector引入XXXRegistrar,XXXRegistrar实现了 ImportBeanDefinitionRegi ...

  7. spring tx:advice事务配置

    http://blog.csdn.net/bao19901210/article/details/17226439 http://blog.csdn.net/rong_wz/article/detai ...

  8. spring tx——TransactionManger

    TransactionDefinition--事务定义 定义事务属性,包括传播级别.隔离级别.名称.超时.只读等 TransactionStatus--事务状态 事务状态,包含事务对象(jdbc为Da ...

  9. Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/tx]

    ERROR - Context initialization failed org.springframework.beans.factory.parsing.BeanDefinitionParsin ...

随机推荐

  1. django 报错处理汇总

    运行 manage.py task时 ,makemigrations抛出以下错误, django.db.utils.OperationalError: (1045, "Access deni ...

  2. dart快速入门教程 (7.1)

    7.面向对象 dart是一门使用类和单继承的面向对象语言,所有的对象都是类的实例,所有的类都是Object的子类,换句话说就是万物皆对象 7.1.类与对象 void main() { // 注意:ne ...

  3. js事件入门(3)

    3.键盘事件 3.1.onkeydown 键盘按下事件 当键盘按下的时候触发 <!DOCTYPE html> <html> <head> <meta char ...

  4. 全国计算机等级考试二级笔试样卷Java语言程序设计

    一.选择题((1)-(35)每小题2分,共70分) 下列各题A).B).C).D)四个选项中,只有一个选项是正确的,请将正确选项涂写在答题卡相应位置上,答在试卷上不得分. (1)下列选项中不符合良好程 ...

  5. 《算法笔记》6.6小节 问题 A: 任务调度

    这道题我一开始看到的时候,想到的是拓补排序,可是这么菜又这么懒的我怎么可能用呢,既然出现在优先队列里面,那么久一定和他有关了 可是并没有使用优先队列 思路: 对于这道题,我们肯定是对他们定义优先级,然 ...

  6. Linux CentOS 7 防火墙/端口设置【转发】

    CentOS升级到7之后用firewall代替了iptables来设置Linux端口, 下面是具体的设置方法: []:选填 <>:必填 [<zone>]:作用域(block.d ...

  7. nodejs 本地压缩jpg,png图片(nodejs)

    使用nodejs实现本地压缩jpg,png图片. 使用到的包 1.images   用于压缩jpg npm install images yarn add images 2.imagemin 用于压缩 ...

  8. Scala数据结构(二)

    一.集合的基础操作 1,head头信息 //获取集合的第一个元素 val list = List(,,) list.head // 2,tail尾信息 //获取集合除去头元素之外的所有元素 val l ...

  9. gulp 如何排除文件和文件夹

    在网上找了好久,很多用gulp-ignore来处理,或者!来处理 经验证,gulp-ignore没有效果,如果有大神路过,还请指教:!一般的写法只能排除单个文件,以下直接写结论 1.如何排除单个文件 ...

  10. CodeFoeces 1215 D Ticket Game(数学,思维)

    CodeFoeces 1215 D Ticket Game 题目大意 M和B轮流玩游戏(每一轮M先手 现在给出一个长度为偶数的串,包含字符'?'和数字 现在两人依次在'?'上填数字\(0\)~\(9\ ...