Spring注解式事务解析


  1. 增加一个Advisor

    首先往Spring容器新增一个Advisor,BeanFactoryTransactionAttributeSourceAdvisor,它包含了TransactionInterceptor通知和TransactionAttributeSourcePointcut切点。TransactionAttributeSourcePointcut切点实际匹配使用了AnnotationTransactionAttributeSource这个类,它的作用是方法的切点匹配,解析Transactional注解,它尝试从当前类的方法,当前类,父接口方法,父接口查找Transactional注解,有则匹配到。

  2. AOP动态代理

    当普通bean实例化的时候,Spring通过AbstractAdvisorAutoProxyCreator的其中一个子类进行postProcessAfterInitialization进行AOP这个bean,织入匹配的Advisor,并生成动态代理。动态代理有2种,JdkDynamicAopProxy和ObjenesisCglibAopProxy。

  3. 拦截过程

    方法调用的时候,拿JdkDynamicAopProxy动态代理来讲,被动态代理的bean的公有方法调用会走invoke方法拦截,首先确定当前方法的拦截器链。

    			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    如果上面的chain为空,不走拦截,否则走拦截责任链

    				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
    retVal = invocation.proceed();
  4. TransactionInterceptor事务拦截器

    内部拿到我们的TransactionInterceptor进行方法调用

    @Override
    public Object invoke(final MethodInvocation invocation) throws Throwable {
    // Work out the target class: may be {@code null}.
    // The TransactionAttributeSource should be passed the target class
    // as well as the method, which may be from an interface.
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction...
    return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
    @Override
    public Object proceedWithInvocation() throws Throwable {
    return invocation.proceed();
    }
    });
    }
5.创建TransactionInfo对象
他会先获取TransactionAttribute和PlatformTransactionManager,然后调用
```
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
```
内部逻辑为拿DataSourceTransactionManager举例,
尝试从ThreadLocal获取ConnectionHolder(包含了一个Connection)
```
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
```
然后判断是不是新事务
```
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
```
不是新事务,走handleExistingTransaction逻辑,内部会根据我们配置的传递规则做不同的处理,默认的Propagation.REQUIRED就会返回TransactionStatus对象标志为已存在的事务。
是新事务则返回TransactionStatus对象标志为新事务,代码如下:
```
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
```
doBegin方法会从dataSource获取一个新连接,并设置到DataSourceTransactionObject的ConnectionHolder字段里,并且设置synchronizedWithTransaction和transactionActive为true代表新事务,然后设置con.setAutoCommit(false),最后设置ThreadLocal值,为当前ConnectionHolder。
```
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
```
6.责任链调用下一个拦截器
获取了当前的TransactionInfo开始走下一个拦截器
```
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
```
7.提交或回滚
处理完了之后如果抛异常根据匹配规则是否需要回滚,默认对RuntimeException和Error回滚。如果正常返回则调用commitTransactionAfterReturning方法
```
protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
```
进行commit,最后调用doCleanupAfterCompletion方法,清空ThreadLocal,设置con.setAutoCommit(true),并关闭连接。

Spring注解式事务解析的更多相关文章

  1. spring + mybatis 注解式事务不回滚的原因分析 @Transactional

    在一个项目中发现spring的事务无法回滚. DEBUG: org.mybatis.spring.SqlSessionUtils - SqlSession [org.apache.ibatis.ses ...

  2. spring中注解式事务不生效的问题

    常用的解决方法可以百度,我针对我的问题描述一下 Mysql中InnoDB引擎才支持事务, MyISAM不支持事务. 当你尝试了各种方法解决spring中注解式事务不生效时, 一定要查看一下数据库中表的 ...

  3. spring+mybatis之注解式事务管理初识(小实例)

    1.上一章,我们谈到了spring+mybatis声明式事务管理,我们在文章末尾提到,在实际项目中,用得更多的是注解式事务管理,这一章将学习一下注解式事务管理的有关知识.注解式事务管理只需要在上一节的 ...

  4. Spring 16: SM(Spring + MyBatis) 注解式事务 与 声明式事务

    Spring事务处理方式 方式1:注解式事务 使用@Transactional注解完成事务控制,此注解可添加到类上,则对类中所有方法执行事务的设定,注解添加到方法上,则对该方法执行事务处理 @Tran ...

  5. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

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

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

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

  7. spring注解式参数校验

    很痛苦遇到大量的参数进行校验,在业务中还要抛出异常或者返回异常时的校验信息,在代码中相当冗长,今天我们就来学习spring注解式参数校验. 其实就是:hibernate的validator. 开始啦. ...

  8. Spring注解开发-全面解析常用注解使用方法之生命周期

    本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ​ ...

  9. -手写Spring注解版本&事务传播行为

    视频参考C:\Users\Administrator\Desktop\蚂蚁3期\[www.zxit8.com] 0018-(每特教育&每特学院&蚂蚁课堂)-3期-源码分析-手写Spri ...

随机推荐

  1. poj-2195(最小费用流)

    题意:给你一个n*m的地图,H代表这个点有一个房子,m代表这个点是一个人,每次h走一步就花费一,问最小花费使得每个人能进入一个房间 代码:建立一个源点和汇点,每个人和源点相连,每个房子和汇点相连,每个 ...

  2. 金融量化之Tushare模块

    一.介绍 Tushare是一个免费.开源的python财经数据接口包.主要实现对股票等金融数据从数据采集.清洗加工 到 数据存储的过程,能够为金融分析人员提供快速.整洁.和多样的便于分析的数据,为他们 ...

  3. JavaScript继承的几种实现

    0 什么是继承 继承就是获得存在对象已有的属性和方法的一种方式. [2019.4.26 更新]今日又重新学习了一下JS的继承,在这里整理一下以前的笔记并补充一些新的感悟. 1 JS中继承的几种实现方法 ...

  4. Java8学习笔记(一)--Lambda表达式

    两个概念 函数式接口 函数式接口就是只显式声明一个抽象方法的接口.为保证方法数量不多不少,java8提供了一个专用注解@FunctionalInterface,这样,当接口中声明的抽象方法多于或少于一 ...

  5. pycharm pip安装包

    第一种方式为命令行模式,在pycharm界面按alt+F12调出命令行窗口,在窗口内输入pip install matplotlib回车即可,如图1所示 方法二:使用菜单项File——settings ...

  6. IIS虚拟目录内的视频文件访问出错:HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。

    MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开.多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式. 我是 ...

  7. css at @ 规则

    css相信我们都不陌生,但是我们真的对它非常了解吗? css主要分为两种规则组成: 一种被称为 at-rule,也就是 at 规则 另一种是 qualified rule,也就是普通规则 今天让我们来 ...

  8. 驱动调试(四)oops确定调用树

    目录 驱动调试(四)oops确定调用树 内核开启调用树 栈指针分析 原理 寄存器别名 基础解释 例子分析 找到PC地址的位置 栈分析 附录:原文的excel title: 驱动调试(四)oops确定调 ...

  9. 关于使用python ~取反操作符带出的一系列问题

    晚上的时候,无意之间看到stackoverflow上面的一个编程挑战赛,各路高手各种搞事,看到python的地方突然发现用了很多位运算的符号,但是~符号引起了我和同事的注意. 我们很少在程序中使用这种 ...

  10. gitlab升级和迁移

    由于近期公司gitlab服务器老是卡顿和出现其他问题,然后也很久没有升级过了,现在版本还是8.10.5,而官网最新版本已经是11.2了.另一个原因是gitlab所在的这台服务器快到期了,想换一台配置更 ...