Spring事务源码分析总结
Spring事务是我们日常工作中经常使用的一项技术,Spring提供了编程、注解、aop切面三种方式供我们使用Spring事务,其中编程式事务因为对代码入侵较大所以不被推荐使用,注解和aop切面的方式可以基于需求自行选择,我们以注解的方式为例来分析Spring事务的原理和源码实现。
//配置事务管理器
<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
@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()
    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);
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);
                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()
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()
@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()
    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()
    private static void registerTransactionManager(Element element, BeanDefinition def) {
        def.getPropertyValues().add("transactionManagerBeanName",
                TxNamespaceHandler.getTransactionManagerName(element));
    }
getTransactionManagerName(element));
tx:annotation-driven/不指定属性的时候,默认去找id固定名为transactionManager的bean作为事务管理器
tatic final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
	static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
	static String getTransactionManagerName(Element element) {
		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
	}
												
											Spring事务源码分析总结的更多相关文章
- [心得体会]spring事务源码分析
		
spring事务源码分析 1. 事务的初始化注册(从 @EnableTransactionManagement 开始) @Import(TransactionManagementConfigurati ...
 - spring事务源码分析结合mybatis源码(一)
		
最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查. spring tx源码分析 这里只分析 ...
 - Spring事务源码分析专题(一)JdbcTemplate使用及源码分析
		
Spring中的数据访问,JdbcTemplate使用及源码分析 前言 本系列文章为事务专栏分析文章,整个事务分析专题将按下面这张图完成 对源码分析前,我希望先介绍一下Spring中数据访问的相关内容 ...
 - spring事务源码分析结合mybatis源码(三)
		
下面将结合mybatis源码来分析下,这种持久化框架是如何对connection使用,来达到spring事务的控制. 想要在把mybatis跟spring整合都需要这样一个jar包:mybatis-s ...
 - Spring事务源码分析
		
首先看例子,这例子摘抄自开涛的跟我学spring3. @Test public void testPlatformTransactionManager() { DefaultTransactionDe ...
 - spring事务源码分析结合mybatis源码(二)
		
让我们继续上篇,分析下如果有第二个调用进入的过程. 代码部分主要是下面这个: if (isExistingTransaction(transaction)) { return handleExisti ...
 - spring事务源码研读1
		
转载摘录自:Spring事务源码分析(一)Spring事务入门 有时为了保证一些操作要么都成功,要么都失败,这就需要事务来保证. 传统的jdbc事务如下: @Test public void test ...
 - 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)
		
一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...
 - Spring AMQP 源码分析 02 - CachingConnectionFactory
		
### 准备 ## 目标 了解 CachingConnectionFactory 在默认缓存模式下的工作原理 ## 前置知识 <Spring AMQP 源码分析 01 - Impatie ...
 
随机推荐
- Jmeter+jenkins如何快速搭建接口和性能测试持续集成解决方案-[基于windows篇]
			
最近在用Jmeter本来想写一个详细的使用教程,突然看到有前辈已经写好了不错的教程,特此"借花献佛"整理出来分享给大家! Jenkins + Jmeter 构建接口.性能测试持续集 ...
 - C#中获取时间差
			
/// <summary> /// 已重载.计算两个日期的时间间隔,返回的是时间间隔的日期差的绝对值. /// </summary> /// <param name=&q ...
 - .net:Code First 创建或更新数据库
			
控制台输入命令: 切换到项目的project.json 文件所在文件 dotnet ef migrations add XXX dotnet ef database update Visual Stu ...
 - java中全面的单例模式多种实现方式总结
			
单例模式的思想 想整理一些 java 并发相关的知识,不知道从哪开始,想起了单例模式中要考虑的线程安全,就从单例模式开始吧. 以前写过单例模式,这里再重新汇总补充整理一下,单例模式的多种实现. 单例模 ...
 - Winter-2-STL-A Argus 解题报告及测试数据
			
Time Limit:2000MS Memory Limit:65536KB Description A data stream is a real-time, continuous, ord ...
 - Docker+.Net Core 的那些事儿-3.创建容器并运行
			
1.根据镜像运行容器 上篇文章建立了一个镜像: 我们以此开始,执行以下命令: docker run -d -p 5000:5000 hwapp:latest 如果返回以上结果表示建立成功. 此时如果你 ...
 - httpd sshd firewalld  很多服务后面的d是什么意思
			
在操作系统中,一般系统的服务都是以后台进程的方式存在,而且都会常驻系统中,直到关机才结束.这类服务也称Daemon,在Linux系统中就包含许多的Daemon. 判断Daemon最简单的方法就是从名称 ...
 - pyinstaller 打包生成的exe文件,在其他电脑上报错
			
解决方法: 1.第一种情况,在打包的时候不要加参数-w,看一下执行exe文件后出现的报错再看下一步的行动 2.应该是需要装一个VC 2015 x64(下载地址:https://www.microsof ...
 - python3_unittest单元测试框架
			
看见英文懵逼,强迫学习英语 The Unittest suppots test automation,sharing of setup and shutdown code of tests, aggr ...
 - Spark高级数据分析· 3推荐引擎
			
推荐算法流程 推荐算法 预备 wget http://www.iro.umontreal.ca/~lisa/datasets/profiledata_06-May-2005.tar.gz cd /Us ...