Spring事务是我们日常工作中经常使用的一项技术,Spring提供了编程、注解、aop切面三种方式供我们使用Spring事务,其中编程式事务因为对代码入侵较大所以不被推荐使用,注解和aop切面的方式可以基于需求自行选择,我们以注解的方式为例来分析Spring事务的原理和源码实现。

  1. //配置事务管理器
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

注意:在需要开启事务的方法上加上@Transactional注解即可,这里需要注意的是,当tx:annotation-driven/标签在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器,如果没有id为transactionManager的bean并且在使用@Transactional注解时也没有指定value(事务管理器),程序就会报错

TxNamespaceHandler

  1. @Override
    public void init() {
       //对tx:advice标签进行解析
    registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
    //对annotation-driven标签进行解析
       registerBeanDefinitionParser("annotation-driven", new         AnnotationDrivenBeanDefinitionParser());
    registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
    }

AnnotationDrivenBeanDefinitionParser.parse()

  1. public BeanDefinition parse(Element element, ParserContext parserContext) {
    registerTransactionalEventListenerFactory(parserContext);
           //对<tx:annotation-driven/> 标签的mode属性进行判断
    String mode = element.getAttribute("mode");
    if ("aspectj".equals(mode)) {
    // mode="aspectj" 提供对aspectj方式进行事务的支持
    registerTransactionAspect(element, parserContext);
    }
    else {
    // mode="proxy"
    AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    }
    return null;
    }

AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);

  1. public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
    //1.表示<tx:annoation-driven/>标签只会被解析一次,只有第一次才剩下
      AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

    String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
    if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
    Object eleSource = parserContext.extractSource(element);

    // Create the TransactionAttributeSource definition.
                  //2.创建AnnotationTransactionAttributeSource
    RootBeanDefinition sourceDef = new RootBeanDefinition(
    "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
    sourceDef.setSource(eleSource);
    sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

    // Create the TransactionInterceptor definition.
                   //3.创建TransactionInterceptor
    RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
    interceptorDef.setSource(eleSource);
    interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    //注册事务管理器
                   registerTransactionManager(element, interceptorDef);
  2.  
  3.                interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
    String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

    // Create the TransactionAttributeSourceAdvisor definition.
                   //4.创建BeanFactoryTransactionAttributeSourceAdvisor,并把前2个添加到属性中
    RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
    advisorDef.setSource(eleSource);
    advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                   
    advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
                   
    advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
    if (element.hasAttribute("order")) {
    advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
    }
    parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

    CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
    compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
    compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
    compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
    parserContext.registerComponent(compositeDef);
    }

上面注册的三个Bean支持了整个事务的功能

registerAutoProxyCreatorIfNecessary()

  1. public static void registerAutoProxyCreatorIfNecessary(
    ParserContext parserContext, Element sourceElement) {
    //注册InfrastructureAdvisorAutoProxyCreator
    BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
    parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    //设置proxy-target-class和expose-proxy的配置
           useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext);
    }

这两个方法的主要目的是注册InfrastructureAdvisorAutoProxyCreator ,这个类间接实现了BeanPostProcessor接口,我们知道,Spring会保证所有bean在实例化的时候都会调用其postProcessAfterInitialization方法,我们可以使用这个方法包装和改变bean,而真正实现这个方法是在其父类AbstractAutoProxyCreator类中:

//实例化userService的Bean就会调用此方法

postProcessAfterInitialization()

  1. @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
    if (bean != null) {
               //根据给定的Bean的class和name构建出key
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    if (!this.earlyProxyReferences.contains(cacheKey)) {
    return wrapIfNecessary(bean, beanName, cacheKey);
    }
    }
    return bean;
    }

wrapIfNecessary()

  1. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    return bean;
    }
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
    }

    // Create proxy if we have advice.
           //获取指定Bean对应的增强器
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
    this.advisedBeans.put(cacheKey, Boolean.TRUE);
    //根据对应的增强器创建代理对象
               Object proxy = createProxy(
    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    this.proxyTypes.put(cacheKey, proxy.getClass());
    return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
    }

registerTransactionManager()

  1. private static void registerTransactionManager(Element element, BeanDefinition def) {
    def.getPropertyValues().add("transactionManagerBeanName",
    TxNamespaceHandler.getTransactionManagerName(element));
    }

getTransactionManagerName(element));

tx:annotation-driven/不指定属性的时候,默认去找id固定名为transactionManager的bean作为事务管理器

  1. tatic final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
  2.  
  3. static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
  4.  
  5. static String getTransactionManagerName(Element element) {
  6. return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
  7. element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
  8. }

Spring事务源码分析总结的更多相关文章

  1. [心得体会]spring事务源码分析

    spring事务源码分析 1. 事务的初始化注册(从 @EnableTransactionManagement 开始) @Import(TransactionManagementConfigurati ...

  2. spring事务源码分析结合mybatis源码(一)

    最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查. spring tx源码分析 这里只分析 ...

  3. Spring事务源码分析专题(一)JdbcTemplate使用及源码分析

    Spring中的数据访问,JdbcTemplate使用及源码分析 前言 本系列文章为事务专栏分析文章,整个事务分析专题将按下面这张图完成 对源码分析前,我希望先介绍一下Spring中数据访问的相关内容 ...

  4. spring事务源码分析结合mybatis源码(三)

    下面将结合mybatis源码来分析下,这种持久化框架是如何对connection使用,来达到spring事务的控制. 想要在把mybatis跟spring整合都需要这样一个jar包:mybatis-s ...

  5. Spring事务源码分析

    首先看例子,这例子摘抄自开涛的跟我学spring3. @Test public void testPlatformTransactionManager() { DefaultTransactionDe ...

  6. spring事务源码分析结合mybatis源码(二)

    让我们继续上篇,分析下如果有第二个调用进入的过程. 代码部分主要是下面这个: if (isExistingTransaction(transaction)) { return handleExisti ...

  7. spring事务源码研读1

    转载摘录自:Spring事务源码分析(一)Spring事务入门 有时为了保证一些操作要么都成功,要么都失败,这就需要事务来保证. 传统的jdbc事务如下: @Test public void test ...

  8. 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)

    一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...

  9. Spring AMQP 源码分析 02 - CachingConnectionFactory

    ### 准备 ## 目标 了解 CachingConnectionFactory 在默认缓存模式下的工作原理   ## 前置知识   <Spring AMQP 源码分析 01 - Impatie ...

随机推荐

  1. 安卓和ios的区别

    安卓不闪退,会卡死,有几率复活,也有可能要强制重启,iOS默认闪退,强制重启的几率小很多. 总的来说,如果要深层次挖掘Android的漏洞就要明白linux内核安全,如果要挖身深层次挖掘iOS的漏洞就 ...

  2. python16_day19【Django_抽屉项目】

    补充ORM块: 1.select_related()  # 解决:当有外健,规避多决查询,使用了join. 多次查询变成一次查询 例:UserInfo.objects.all().select_rel ...

  3. javascript 类型 内存 对象

    var box =0 function test() { alert(box) //全局 }

  4. 性能调优之MySQL篇一:MySQL性能计数器

    计数器 计数器分析 Threads_connected 表示当前有多少个客户连接该mysql服务器,连接数是否过多,网络是否存在问题,它是动态变化的,当达到最大连接数时,数据库系统就不能提供更多的连接 ...

  5. 两个java小练习

    网上看到的一个小练习,自己写了一个,但是时间限制并不符合,并且貌似还有些小问题,暂时放在这儿,代码格式什么的也不太规范. 1.班级排名时间限制: 1000ms 内存限制: 65536kB 描述 信息科 ...

  6. HDFS数据块

    磁盘也是由数据块组成的,一般默认大小是512字节,构建磁盘之上的文件系统一般是磁盘块的整数倍.         HDFS也是采用块管理的,但是比较大,在Hadoop1.x中默认大小是64M,Hadoo ...

  7. Atom插件无法下载安装解决办法,Atom使用教程,Atom常用插件

    使用教程http://wiki.jikexueyuan.com/project/atom/plug-in.html atom通过setting中无法下载插件,通过apm也无法下载插件,可能是网络.co ...

  8. mysql 手动安装和管理

    版本:5.7.10 my.ini简单配置 [client] default-character-set=utf8 [mysqld] port = 3306 basedir =D:/programs/M ...

  9. 基于tomcat集群做session共享

    前端代理服务器nginx:192.168.223.136 tomcat服务器:采用的一台多实例192.168.223.146:8081,192.168.223.146:8082(如何构建多实例tomc ...

  10. 20145307JAVA学习期末总结

    20145307<Java程序设计>课程总结 每周读书笔记链接汇总 20145307 <Java程序设计>第一周学习总结:http://www.cnblogs.com/Jcle ...