精华内容
下载资源
问答
  • 本资源讲解的是Spring事务的相关技术,需要可自行下载。 课程内容: 1.实战了解学习源码应有的姿势? 2.埋坑,从深坑中玩转事务; 3.迷一般的事务?我数据验证为啥失效? 4.透过源码学习事务隔离级别; 5.源码解读,...
  • Spring事务源码分析

    2017-03-30 13:51:38
    Spring事务在执行过程中, 会有两个拦截器, 第一个是TransactionInterceptor,即事务拦截器,他的targetClass是标注@Transactional方法所在的class,方法为标注@Transactional的方法。然后在target方法之前执行...
    Spring事务在执行过程中, 会有两个拦截器, 第一个是TransactionInterceptor,即事务拦截器,他的targetClass是标注@Transactional方法所在的class,方法为标注@Transactional的方法。然后在target方法之前执行DataSourceTransactionManager的doBegin()方法。doBegin方法完成的任务是将connection的自动提交改为false,将DataSourceTransactionObject的connectionHolder的事务属性设为active, 设置事务的超时时间,隔离级别,只读等属性。开始执行@Tranactional标注的方法里的语句,到下一个拦截器:MapperProxy,做了一些我看不懂的操作,然后触发下一个拦截器:sqlSessionInterceptor, 调用Executor去执行sql语句, 如果抛除了异常,则回到TransactionInterceptor,根据回滚规则决定是否回滚,满足回滚条件,由DataSourceTransactionManager执行回滚:由Transaction synchronization来回滚SqlSession然后关闭SqlSession, DataSourceTransactionManager释放数据库连接。
    展开全文
  • spring学习事务源码

    2018-06-02 09:17:48
    spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码
  • Spring源码分析-Spring事务源码分析

    千次阅读 2020-08-24 15:35:39
      在配置Spring事务管理的时候会用到一个类TransactionInterceptor,从下面的类关系图中可以看到TransactionInterceptor继承了MethodInterceptor接口,而MethodInterceptor接口是属于AOP功能模块的接口它其中提供...

    导语
      

      在配置Spring事务管理的时候会用到一个类TransactionInterceptor,从下面的类关系图中可以看到TransactionInterceptor继承了MethodInterceptor接口,而MethodInterceptor接口是属于AOP功能模块的接口它其中提供了一个方法Object invoke(MethodInvocation invocation) throws Throwable;那么既然TransactionInterceptor继承了这个接口就要实现这个方法,这里就从这个方法开始入手。
    在这里插入图片描述

      找到该方法之后,通过IDEA的提示,会看到首先这个方法是从父类继承过来的,其次这个方法是一个切点方法,也就是说做AOP操作的时候需要识别的就是这个方法。而方法体内也是有获取目标类的操作。并且调用了invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed)方法,而这个方法在本类中并没有出现,它是父类TransactionAspectSupport的方法。
    在这里插入图片描述
      invokeWithinTransaction()方法如下图所示
    在这里插入图片描述
      其中最主要的的需要进行分析的一个方法就是TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification),它根据事务的传播性对事务进行不同的处理,核心的方式是通过TransactionStatus 来判断事务的属性。方法内容如下
    在这里插入图片描述
      它其中调用了PlatformTransactionManager 接口的getTransaction(txAttr) 方法,这里是调用其子类中的getTransaction(txAttr)方法,方法继承规则如下
    在这里插入图片描述
      在该方法中调用了DataSourceTransactionManager的doGetTransaction()方法如下,它是根据DataSource 数据源获取DataSourceTransactionObject 对象。
    在这里插入图片描述

      看完doGetTransaction()方法就来分析一下doBegin()开启事务方法。
    在这里插入图片描述

      在doGetTransaction()方法中,如果同一个线程再次进入执行事务,那么将会获取到同一个ConnectionHolder。而回到 invokeWithinTransaction()方法中,接下来就会执行retVal = invocation.proceedWithInvocation() 方法,而这个方法的调用是调用了ReflectiveMethodInvocation类的proceed()方法,这个就是动态代理中用到的对象执行部分的代码了。

      执行完上面的方法之后,就会执行提交或者回滚操作。如下
    在这里插入图片描述
      其中最关键的就是txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());代码,调用的是AbstractPlatFormTransactionManager类的commit()方法。
    在这里插入图片描述
      然后最终会调用到一个processCommit()方法中。会看到在整个方法中,调用了一个doCommit的方法,并且传入的是前面提到的事务状态。调用了DataSourceTransactionManager中的doCommit()方法。
    在这里插入图片描述
      最终都会调用到DataSourceTransactionManager()的doCommit()方法
    在这里插入图片描述

    总结

      对于Spring事务管理是SpringAOP的应用关键点,在企业的开发中也是比较广泛的,对于Spring事务源码的分析也是对Spring事务管理的一大帮助,主要用到的就是Spring AOP动态代理技术,当然对于动态代理机制,在后续的分享学习中博主会继续总结。而对于Spring事务管理出了理解源码以外还需要理解事务的隔离级别和事务的传播行为,在上面分析源码的过程中都有所体现。当然理论基础也是实践的基础,上面的源码就是基于理论的实践。

    展开全文
  • Starting from a joke ...问:实现Spring事务,分几步? 答:三步啊,第一、找出需要事务的方法,第二、把事务加进去,第三、执行事务。 You may find it's not a joke, it's serious。 Try to find an entr...

    Starting from a joke

     


    问:把大象放冰箱里,分几步?

    答:三步啊,第一、把冰箱门打开,第二、把大象放进去,第三、把冰箱门带上。

    问:实现Spring事务,分几步?

    答:三步啊,第一、找出需要事务的方法,第二、把事务加进去,第三、执行事务。

    You may find it's not a joke, it's serious。

     

    Try to find an entrance



    当你面对一个完全不熟悉的事物时,一定要想办法找到一个突破口,然后逐步深入。那Spring事物的突破口在哪里呢?很明显在@EnableTransactionManagement注解里,因为是它启用了事物功能。

    请看下图:

     


    发现注解还引入了一个类TransactionManagementConfigurationSelector。

    再来看这个类,如下图:

     


    发现如果采用代理的方式时,又引入了一个类ProxyTransactionManagementConfiguration。

    接着看这个类(重点来了),如下图:

     

     

    发现这个类往容器中注册了3个bean,第一个是BeanFactoryTransactionAttributeSourceAdvisor。它以Advisor结尾说明它是Spring AOP范畴里的东西。

    在AOP里,Advisor = Pointcut + Advice,Pointcut是切入点,表示要拦截的方法,Advice是增强,表示要加进去的事物功能。

    再看看另外两个注册的bean,就是和这两个相关的。其中TransactionInterceptor就是一个Advice,因为它实现了Advice接口,包含了把事物加进去的逻辑。

    TransactionAttributeSource虽然不是一个Pointcut,但是它被Pointcut所用,用于检测一个类的方法上是否有@Transactional注解,来确定该方法是否需要事物增强。

    从下图中也可以看出这一点:

     


    可以看到这个bean通过下面的set方法被设置进去,然后又用在了Pointcut的类里了。

    整体来看,此部分的结构和功能划分还是非常清晰的。下面来逐一研究。
     

    AOP切点



    TransactionAttributeSourcePointcut类以Pointcut结尾,说明它是一个切入点,就是标识要被拦截的方法。类名的前缀部分表明了这个切入点的实现原理。

    看下这个前缀是TransactionAttributeSource,它以Source结尾,说明它是一个源(即源泉,有向外提供东西的意思)。它的前缀是TransactionAttribute,即事务属性。

    由此可见,这个源可以向外提供事务属性,其实就是判断一个类的方法上是否标有@Transactional注解,如果有的话还可以获取这个注解的属性(即事务属性)。

    整体来说就是,Pointcut拦截住了方法,然后使用这个“源”去方法和类上获取事务属性,如果能获取到,说明此方法需要参与事务,则进行事务增强,反之则不增强。

    下面这张图可以证明我们的想法:

     


    可以看出matches方法的两个参数就是一个方法(Method)和一个类(Class<?>)。最后从方法和类上获取事务属性,再进行是否为null判断。

    现在这个“源”还是个黑盒子,下面来揭开它的面纱。它的实现类是AnnotationTransactionAttributeSource,以Annotation开头,说明是基于注解实现的。

    下面图是它的源码的一部分:

     


    第一个方法从类上找事务属性,第二个方法从方法上找事务属性,它俩都调用了第三个方法来实现。

    PS:我们都知道,方法上的注解优先级高于类上的,是因为找注解时先找方法上的,找不到时再去类上找。所以方法上的优先级高。此部分代码逻辑在父类里写着呢,这里不再展示了。

    第三个方法使用多个事务注解解析器(TransactionAnnotationParser)去解析注解,为啥是多个解析器呢?因为事务注解不仅Spring提供了,Java后来也提供了,就是javax.transaction.Transactional。

    Spring对自己注解的解析器实现类是SpringTransactionAnnotationParser,如下图:

     


    可以看出使用工具类来读取注解@Transactional的属性,然后逐个解析出属性值并进行类型转换,接着把这些属性封装到一个类里,这个类其实就是事务属性,即TransactionAttribute。

    这个事务属性继承了事务定义接口,事务定义接口我们应该都很熟悉,如下图:

     


    这也证明了以前文章里说过的话,@Transactional注解的作用有两个,一是表明要参与事务,二是表明如何参与事务,这些注解属性就是来规定如何参与的。

    这个事务属性TransactionAttribute是个接口,它的实现类在这里就不再详说了。
     

    AOP增强



    Advice就是AOP中的增强,TransactionInterceptor实现了Advice接口,所以它就是事务增强。

    先来看下该接口,如下图:

     


    发现它只是一个空的标记接口。而且它的包名是org.aopalliance,是一个AOP联盟组织,它制定的AOP规范。

    先来了解下AOP领域的一些相关内容,Pointcut是切入点,表示要拦截的方法。它是一个静态的概念,即程序不运行时它也是存在的。

    那么在真正运行时,已经拦截住了,此时该怎么表示这个情况呢?是用Joinpoint来表示的,所以Joinpoint是一个运行时的概念,只有在运行时才存在。

    请看Joinpoint接口,如下图:

     


    第一个方法proceed()是“继续”的意思,调用它表示去执行被拦截住的方法本身,返回方法本身的返回值。

    第二个方法getThis()是获取this对象,即方法运行时所在的目标对象。如果是静态方法,则为null,因为静态方法是属于类本身的,运行时不需要对象。

    第三个方法getStaticPart(),其实就表示了被拦截住的方法,即就是一个Method。Method其实算是“元数据”,是属于类型本身的,也有“静态”的意思。

    再看一个接口,Invocation,它继承了Joinpoint,如下图:

     


    方法getArguments()就表示运行时传递给被拦截住方法的参数。

    再看一个接口,MethodInvocation,它继承了Invocation,如下图:

     


    方法getMethod()返回一个Method,它就是当前正在执行的方法,是对本拦截方法的一个友好实现,返回相同的结果。

    可见MethodInvocation接口已经包含了一个方法调用的全量信息,方法,参数,目标对象。这其实就是运行时被拦截住的东西。

    再看下面这个接口,MethodInterceptor,方法拦截器,如下图:

     


    它只有一个方法invoke,方法参数就是上面介绍的MethodInvocation。所以拦截器可以使用这个参数来对目标方法进行调用,当然在调用前/后可以加入自己的逻辑。

    TransactionInterceptor类就实现了这个接口,因此可以在对目标方法的调用前后插入事务逻辑代码来进行事务增强。

    下面是事务拦截器对该方法的实现,如下图:

     


    它调用的invokeWithinTransaction方法是在父类里的,看下图:

     


    这个图里做的事情较多,逐个来看:

    前两行获取事务属性“源”,再用这个“源”来获取事务属性。咦,有点奇怪,上面不是已经获取过了吗?是的,上面是在Pointcut里获取的,那只是用于判断那个方法是否要被拦截而已。这里获取的属性才是真正用于事务的。

    第三行是根据事务属性,来确定出一个事务管理器来。

    接下来是使用事务管理器打开事务。

    接下来是对被拦截住的目标方法的调用执行,当然要try/catch住这个执行。

    如果抛出了异常,则进行和异常相关的事务处理,然后将这个异常继续向上抛出。

    如果没有抛出异常,则进行事务提交。

    最后的else分支是对编程式事务的调用,事务的打开/提交/回滚是开发人员自己写代码控制,所以就不需要事务管理器操心了。

    下面请看和异常相关的事务处理,如下图:

     


    判断异常类型是否需要回滚,需要的话就回滚事务,不需要的话就继续提交事务。

    这里的整体结构和逻辑流程也是比较清晰的,那是因为一方面得益于AOP领域的概念,另一方面是事务管理器屏蔽了事务的所有复杂性。

    PS:事务管理器的内容其实还是挺复杂的,下篇文章再详细解说。

     

    如果你对编程感兴趣或者想往编程方向发展,可以关注微信公众号【筑梦编程】,大家一起交流讨论!小编也会每天定时更新既有趣又有用的编程知识!

     

    (END)

    展开全文
  • 文章目录概述源码解析xml 配置解析事务代理类的创建事务拦截器的实现切面实现事务处理实现总结:资料 概述 事务处理是一个重要并且涉及范围很广的领域,涉及到并发和数据一致性方面的问题。作为应用平台的 Spring ...

    概述

    事务处理是一个重要并且涉及范围很广的领域,涉及到并发和数据一致性方面的问题。作为应用平台的 Spring 具有在多种环境中配置和使用事务处理的能力,也就是说通过使用 Spring 的事务处理,可以把事务处理的工作统一起来,为事务处理提供统一支持。

    由于这方面的内容比较多,这里只讲事务处理中最为基本的使用场景,即 Spring 是怎样实现对单个数据库局部事务处理的。

    在 Spring 中,既支持编程式事务管理方式,又支持声明式事务处理方式。编程式事务管理代码如下所示:

    Connection conn = null;
    UserTransaction tx = null;
    try {
        tx = getUserTransaction();                       //1.获取事务
        tx.begin();                                    //2.开启JTA事务
        conn = getDataSource().getConnection();           //3.获取JDBC
        // 4.声明SQL
        String sql = "select * from INFORMATION_SCHEMA.SYSTEM_TABLES";
        PreparedStatement pstmt = conn.prepareStatement(sql);//5.预编译SQL
        ResultSet rs = pstmt.executeQuery();               //6.执行SQL
        process(rs);                                   //7.处理结果集
        closeResultSet(rs);                             //8.释放结果集
        tx.commit();                                  //7.提交事务
    } catch (Exception e) {
        tx.rollback();                                 //8.回滚事务
        throw e;
    } finally {
       conn.close();                                //关闭连接
    }
    

    也就是把事务的开始、提交、回滚显式的写到了代码里。这种方式好处是灵活,缺点是啰嗦,对开发人员要求较高,稍有不慎就写出故障来了。

    Spring 中的声明式事务处理是用户最常用的,通过将事务处理的过程和业务代码分离开来,大大简化了代码的编写。声明式事务有两种使用方式,第一种是纯粹的 xml 文件配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p"
    	xsi:schemaLocation="  
               http://www.springframework.org/schema/beans  
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
               http://www.springframework.org/schema/aop  
               http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
               http://www.springframework.org/schema/context  
               http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    	<!-- 配置数据源 -->
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    		<property name="url" value="jdbc:mysql://localhost:3306/test" />
    		<property name="username" value="root" />
    		<property name="password" value="christmas258@" />
    	</bean>
    	<!--配置一个JdbcTemplate实例,并将这个“共享的”,“安全的”实例注入到不同的DAO类中去 -->
    	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    	<!-- 声明事务管理器 -->
    	<bean id="txManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    	<!-- 需要实施事务增强的目标业务Bean -->
    	<bean id="libraryTarget" class="com.mucfc.dao.LibraryDaoImpl"
    		p:jdbcTemplate-ref="jdbcTemplate" />
     
    	<!-- 使用事务代理工厂类为目标业务Bean提供事务增强 -->
    	<bean id="libraryFactory"
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
    		p:transactionManager-ref="txManager" p:target-ref="libraryTarget">
    		<!-- 事务属性配置 -->
    		<property name="transactionAttributes">
    			<props>
    				<!-- 以get开头的方法采用只读型事务控制类型 -->
    				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
    				<!-- 所有方法均进行事务控制,如果当前没有事务,则新建一个事务 -->
    			<prop key="addBook">PROPAGATION_REQUIRED</prop>
    			</props>
    		</property>
     
    	</bean>
    </beans>
    

    在这里配置了数据源 dataSource、事务管理器 transactionManager、待事务增强的目标业务 Bean、事务增强配置。第二种是注解方式,不过 xml 中依然需要配置数据源 dataSource 和事务管理器 transactionManager,额外还需要加上 annotation-driven 配置。

    @Transactional
    public void run() {
    	// DB 操作
    }
    
    <tx:annotation-driven/>
    

    源码解析

    这里,我们以注解方式为例,讲一下声明式事务的实现原理。注解方式的声明式事务本质上是把编程式事务中原本需要用户自己写的代码进行了封装,并通过 AOP 的方式来生成了具体业务类的代理类。

    xml 配置解析

    无论是纯粹 xml 配置,还是注解加配置的方式,都需要 Spring 通过 TxNamespaceHandler 来解析事务标签,代码如下所示:

    public class TxNamespaceHandler extends NamespaceHandlerSupport {
    	static 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);
    	}
    
    	@Override
    	public void init() {
    		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
    		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
    		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
    	}
    }
    

    从代码中可知,annotation-driven 标签是由 AnnotationDrivenBeanDefinitionParser 类来解析的。首先 tx:annotation-driven 有一个 model 属性,有两个值 proxy 和 aspectj。该类根据 xml 配置来决定加载哪些 AOP 相关类。

    下面以 proxy 方式为例,说一下都加载了哪些类?

    	private static class AopAutoProxyConfigurer {
    		public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
    			// 注册 InfrastructureAdvisorAutoProxyCreator 类
    			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
    
    			String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
    			if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
    				Object eleSource = parserContext.extractSource(element);
    
    				// 注册 AnnotationTransactionAttributeSource 类.
    				RootBeanDefinition sourceDef = new RootBeanDefinition(
    						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
    				sourceDef.setSource(eleSource);
    				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
    
    				// 注册 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);
    
    				// 注册 TransactionAttributeSourceAdvisor 类.
    				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);
    			}
    		}
    	}
    

    在这里注册了四个类:

    1. InfrastructureAdvisorAutoProxyCreator:实现了 BeanPostProcessor 接口,在 postProcessAfterInitialization 方法中会根据需要创建 Proxy 类。
    2. AnnotationTransactionAttributeSource:解析事务类,得到事务配置相关信息。
    3. TransactionInterceptor:事务拦截器,实现了 Advice、MethodInterceptor 接口。
    4. BeanFactoryTransactionAttributeSourceAdvisor:实现了 PointcutAdvisor 接口,依赖 TransactionInterceptor 和 TransactionAttributeSourcePointcut。

    事务代理类的创建

    Spring 在创建 bean 之后,会执行 BeanPostProcessor 的 postProcessAfterInitialization 方法。而 InfrastructureAdvisorAutoProxyCreator 继承了 AbstractAutoProxyCreator 类,AbstractAutoProxyCreator 实现了 BeanPostProcessor 接口:

    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		if (bean != null) {
    			Object cacheKey = getCacheKey(bean.getClass(), beanName);
    			if (!this.earlyProxyReferences.contains(cacheKey)) {
    				return wrapIfNecessary(bean, beanName, cacheKey);
    			}
    		}
    		return bean;
    	}
    	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    		// 查找适合此 bean 的 advisor
    		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;
    	}
    

    如何查找适合某个 bean 的 advisor 呢?可以看下面的代码:

    	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
    		// 查找适合此 bean 的 advisor
    		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    		if (advisors.isEmpty()) {
    			return DO_NOT_PROXY;
    		}
    		return advisors.toArray();
    	}
    	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    		List<Advisor> candidateAdvisors = findCandidateAdvisors();
    		// 查找适合此 bean 的 advisor
    		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    		extendAdvisors(eligibleAdvisors);
    		if (!eligibleAdvisors.isEmpty()) {
    			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    		}
    		return eligibleAdvisors;
    	}
    	protected List<Advisor> findAdvisorsThatCanApply(
    			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
    		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    		try {
    			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
    		} finally {
    			ProxyCreationContext.setCurrentProxiedBeanName(null);
    		}
    	}
    	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    		List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
    		for (Advisor candidate : candidateAdvisors) {
    			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
    				eligibleAdvisors.add(candidate);
    			}
    		}
    		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    		for (Advisor candidate : candidateAdvisors) {
    			if (candidate instanceof IntroductionAdvisor) {
    				continue;
    			}
    			if (canApply(candidate, clazz, hasIntroductions)) {
    				eligibleAdvisors.add(candidate);
    			}
    		}
    		return eligibleAdvisors;
    	}
    	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    		if (advisor instanceof IntroductionAdvisor) {
    			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    		} else if (advisor instanceof PointcutAdvisor) {
    			PointcutAdvisor pca = (PointcutAdvisor) advisor;
    			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    		} else {
    			// It doesn't have a pointcut so we assume it applies.
    			return true;
    		}
    	}
    	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    		Assert.notNull(pc, "Pointcut must not be null");
    		if (!pc.getClassFilter().matches(targetClass)) {
    			return false;
    		}
    
    		MethodMatcher methodMatcher = pc.getMethodMatcher();
    		if (methodMatcher == MethodMatcher.TRUE) {
    			// No need to iterate the methods if we're matching any method anyway...
    			return true;
    		}
    		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
    			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    		}
    		Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    		classes.add(targetClass);
    		for (Class<?> clazz : classes) {
    			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    			for (Method method : methods) {
    				if ((introductionAwareMethodMatcher != null &&
    						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
    						methodMatcher.matches(method, targetClass)) {
    					return true;
    				}
    			}
    		}
    		return false;
    	}
    

    看到最后,可以知道有两种方法可以判断:

    1. Pointcut.getMethodMatcher().matches();
    2. IntroductionAdvisor.getClassFilter().matches。

    事务拦截器的实现

    在前面提到过,注册了 BeanFactoryTransactionAttributeSourceAdvisor 类,该类实现了 PointcutAdvisor 接口,其中的切面 pointcut 便是通过 TransactionAttributeSourcePointcut 来实现的。TransactionAttributeSourcePointcut 的 matches 方法是根据能否可以从目标 bean 中得到 TransactionAttribute 来判断是否匹配的。

    public interface PointcutAdvisor extends Advisor {
    	Pointcut getPointcut();
    }
    public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    	private TransactionAttributeSource transactionAttributeSource;
    	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
    		@Override
    		protected TransactionAttributeSource getTransactionAttributeSource() {
    			return transactionAttributeSource;
    		}
    	};
    }
    abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
    	@Override
    	public boolean matches(Method method, Class<?> targetClass) {
    		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
    			return false;
    		}
    		TransactionAttributeSource tas = getTransactionAttributeSource();
    		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    	}
    }
    

    TransactionAttributeSource 的实现类主要是 AnnotationTransactionAttributeSource,该类使用 SpringTransactionAnnotationParser 类解析注解 Transactional 得到 TransactionAttribute:

    	// 在 SpringTransactionAnnotationParser 类中
    	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    		AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
    				element, Transactional.class);
    		if (attributes != null) {
    			return parseTransactionAnnotation(attributes);
    		}
    		else {
    			return null;
    		}
    	}
    	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    
    		Propagation propagation = attributes.getEnum("propagation");
    		rbta.setPropagationBehavior(propagation.value());
    		Isolation isolation = attributes.getEnum("isolation");
    		rbta.setIsolationLevel(isolation.value());
    		rbta.setTimeout(attributes.getNumber("timeout").intValue());
    		rbta.setReadOnly(attributes.getBoolean("readOnly"));
    		rbta.setQualifier(attributes.getString("value"));
    
    		List<RollbackRuleAttribute> rollbackRules = new ArrayList<RollbackRuleAttribute>();
    		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
    			rollbackRules.add(new RollbackRuleAttribute(rbRule));
    		}
    		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
    			rollbackRules.add(new RollbackRuleAttribute(rbRule));
    		}
    		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
    			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
    		}
    		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
    			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
    		}
    		rbta.setRollbackRules(rollbackRules);
    
    		return rbta;
    	}
    

    切面实现

    前面讲了如何判断一个类是否需要创建事务处理的代理类,下面讲一下用于实现事务处理的切面实现。

    TransactionInterceptor 实现了方法拦截器 MethodInterceptor 接口,用于对业务类进行事务增强。TransactionInterceptor 的 invoke 方法主要是调用了父类 TransactionAspectSupport 的 invokeWithinTransaction 方法。

    	@Override
    	public Object invoke(final MethodInvocation invocation) throws Throwable {
    		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
    			@Override
    			public Object proceedWithInvocation() throws Throwable {
    				return invocation.proceed();
    			}
    		});
    	}
    	protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
    		// 获取事务配置信息
    		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    		// 获取事务管理器
    		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    		// 同步操作
    		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
    			// 创建事务类
    			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    			Object retVal = null;
    			try {
    				// 环绕增强:触发链条上的下一个拦截器,最终会调用目标类
    				retVal = invocation.proceedWithInvocation();
    			} catch (Throwable ex) {
    				// 出现异常则回滚
    				completeTransactionAfterThrowing(txInfo, ex);
    				throw ex;
    			} finally {
    				cleanupTransactionInfo(txInfo);
    			}
    			commitTransactionAfterReturning(txInfo);
    			return retVal;
    		} else {
    			// 省略异步操作,原理类似
    		}
    	}
    

    invoke 方法里主要做以下几件事:

    1. 获取事务属性;
    2. 获取事务管理器;
    3. 创建事务;
    4. 执行目标方法;
    5. 遇到异常则回滚,正常结束则提交。

    事务处理实现

    对于具体的事务处理实现,比如事务的生成、提交、回滚、挂起等,由于不同的底层数据库有不同的支持方式,因此在 Spring 事务处理中,对主要的事务实现做了一个抽象和适配。Spring 设计了 PlatformTransactionManager 接口,抽象出事务管理的主要功能:提交、回滚,并提供了针对不同数据源的实现:针对 DataSource 数据源的 DataSourceTransactionManager、针对 Hibernate 数据源的 HibernateTransactionManager、针对 JDO 数据源的 JdoTransactionManager 等等。

    public interface PlatformTransactionManager {
    	// 获取事务对象 TransactionStatus,如果没有就创建一个
    	TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
    	// 提交
    	void commit(TransactionStatus status) throws TransactionException;
    	// 回滚
    	void rollback(TransactionStatus status) throws TransactionException;
    }
    

    下面分析一下最常见的 DataSourceTransactionManager,该类继承自 AbstractPlatformTransactionManager,AbstractPlatformTransactionManager 实现了 PlatformTransactionManager 接口,

    	@Override
    	protected void doCommit(DefaultTransactionStatus status) {
    		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    		Connection con = txObject.getConnectionHolder().getConnection();
    		try {
    			con.commit();
    		} catch (SQLException ex) {
    			throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    		}
    	}
    	@Override
    	protected void doRollback(DefaultTransactionStatus status) {
    		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    		Connection con = txObject.getConnectionHolder().getConnection();
    		try {
    			con.rollback();
    		} catch (SQLException ex) {
    			throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    		}
    	}
    

    提交和回滚都比较简单,主要是调用了 Connection 的对应类。下面我们详细看一下 getTransaction 的实现:

    	public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
    		// 获取事务(如果当前已经存在的话)
    		Object transaction = doGetTransaction();
    
    		if (definition == null) {
    			// Use defaults if no transaction definition given.
    			definition = new DefaultTransactionDefinition();
    		}
    		// 如果当前线程已经存在事务,需要特殊处理
    		if (isExistingTransaction(transaction)) {
    			return handleExistingTransaction(definition, transaction, debugEnabled);
    		}
    		// PROPAGATION_MANDATORY 表示支持当前事务,如果当前没有事务,就抛出异常。
    		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
    			throw new IllegalTransactionStateException(
    					"No existing transaction found for transaction marked with propagation 'mandatory'");
    		} else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
    				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
    				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    			SuspendedResourcesHolder suspendedResources = suspend(null);
    			try {
    				// 创建新事务
    				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    				DefaultTransactionStatus status = newTransactionStatus(
    						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    				doBegin(transaction, definition);
    				prepareSynchronization(status, definition);
    				return status;
    			} catch (RuntimeException ex) {
    				resume(null, suspendedResources);
    				throw ex;
    			} catch (Error err) {
    				resume(null, suspendedResources);
    				throw err;
    			}
    		} else {
    			// 创建空事务
    			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
    			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
    		}
    	}
    
    	// 当事务已经存在时,处理最为复杂
    	private TransactionStatus handleExistingTransaction(
    			TransactionDefinition definition, Object transaction, boolean debugEnabled)
    			throws TransactionException {
    		// PROPAGATION_NEVER 表示必须以非事务方式运行,如果已经存在事务,则抛出异常
    		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
    			throw new IllegalTransactionStateException(
    					"Existing transaction found for transaction marked with propagation 'never'");
    		}
    		// PROPAGATION_NOT_SUPPORTED 表示以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
    		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
    			Object suspendedResources = suspend(transaction);
    			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
    			return prepareTransactionStatus(
    					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
    		}
    		// PROPAGATION_REQUIRES_NEW 表示新建事务,如果当前存在事务,把当前事务挂起
    		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
    			SuspendedResourcesHolder suspendedResources = suspend(transaction);
    			try {
    				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    				DefaultTransactionStatus status = newTransactionStatus(
    						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    				doBegin(transaction, definition);
    				prepareSynchronization(status, definition);
    				return status;
    			} catch (RuntimeException beginEx) {
    				resumeAfterBeginException(transaction, suspendedResources, beginEx);
    				throw beginEx;
    			} catch (Error beginErr) {
    				resumeAfterBeginException(transaction, suspendedResources, beginErr);
    				throw beginErr;
    			}
    		}
    		// PROPAGATION_NESTED 表示如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作
    		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    			if (!isNestedTransactionAllowed()) {
    				throw new NestedTransactionNotSupportedException(
    						"Transaction manager does not allow nested transactions by default - " +
    						"specify 'nestedTransactionAllowed' property with value 'true'");
    			}
    			if (useSavepointForNestedTransaction()) {
    				// 如果支持 Savepoint,则创建 Savepoint
    				DefaultTransactionStatus status =
    						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
    				status.createAndHoldSavepoint();
    				return status;
    			} else {
    				// 创建新事务
    				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    				DefaultTransactionStatus status = newTransactionStatus(
    						definition, transaction, true, newSynchronization, debugEnabled, null);
    				doBegin(transaction, definition);
    				prepareSynchronization(status, definition);
    				return status;
    			}
    		}
    		// 合法性校验
    		if (isValidateExistingTransaction()) {
    			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
    				Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
    				if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
    					Constants isoConstants = DefaultTransactionDefinition.constants;
    					throw new IllegalTransactionStateException("Participating transaction with definition [" +
    							definition + "] specifies isolation level which is incompatible with existing transaction: " +
    							(currentIsolationLevel != null ?
    									isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
    									"(unknown)"));
    				}
    			}
    			if (!definition.isReadOnly()) {
    				if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
    					throw new IllegalTransactionStateException("Participating transaction with definition [" +
    							definition + "] is not marked as read-only but existing transaction is");
    				}
    			}
    		}
    		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
    	}
    

    总结:

    Spring 事务处理模块主要类之间的关系如下图所示:

    Spring 事务处理模块类图

    资料

    1. spring事物的七种事物传播属性行为及五种隔离级别
    2. Spring 技术内幕
    展开全文
  • 1.环境搭建 依赖jar包 <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> ...
  • @Transactional Spring事务源码分析 本文讲解了Spring中最常用的注解@Transactional的各项属性的用法,分析了编程式事务和声明式事务的区别。并在源码的基础上分析了事务的实现机制,对了解事务的使用、彻底理解事务...
  • Spring事务源码分析,Spring源代码流程,跟着文档看源码,思路清晰
  • Spring事务源码解析之事务提交篇

    千次阅读 2018-01-14 20:04:24
    Spring源码版本:4.3.8 注释规则: //单行注释做普通注释 /**/多行注释做深入分析 建议配合Spring源码阅读 正文承接上文,我们来看事务的提交操作: TransactionAspectSupport:protected void ...
  • Spring事务实现原理及源码分析

    万次阅读 多人点赞 2019-04-04 17:29:05
    Spring事务实现原理及源码分析流程介绍主流程关键对象介绍PlatformTransactionManager获取对应的TransactionManager事务的信息TransactionInfo当前事务状态TransactionStatus传播对象实现原理隔离级别对开始事务的...
  • Spring 事务执行过程源码解析

    千次阅读 2021-03-25 22:51:00
    引言 概述: AOP系列文章: 【1】Spring Aop初始化源码分析 【2】Spring AOP创建代理对象源码解析 【3】Spring AOP 链式调用过程源码解析 【4】Spring 事务执行过程源码解析 1 工程 1.1 数据库 CREATE TABLE `t_...
  • 基于最新Spring 5.x,详细介绍了Spring 事务源码,包括BeanFactoryTransactionAttributeSourceAdvisor注解事务通知器源码解析。
  • 搭建Spring源码调试环境的工具,亲测有效,遇到的问题都解决了呢!
  • 文章目录1 通过注解方式配置数据+事务管理器+持久层框架2 spring事务核心组件的注册2.1 @EnableTransactionManagement注解2.2 TransactionManagementConfigurationSelector类2.3 ...-- 三大核心组件2.4 ...
  • 本博客分为两点,一个是spring事务实现原理源码解读(个人能力,初步解读),二是spring事务的传播属性   简单案例,保存订单,修改商品数量 就是这两个方法,第一个方法中引用了第二个方法,都用@...
  • 终于等到了B站的薪资沟通电话,美滋滋,本节开始进入Spring数据访问篇,讲解spring事务,文章参考自Tom老师视频。 事务基本概念 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 ...
  • 最近回顾了一下Spring源码,准备用思维导图的方式简单的将整个源码内容的流程展示出来,思维导图、图片等文件更新在https://github.com/MrSorrow/spring-framework仓库中,阅读博客不方便可以直接下载。 思维导图...
  • 基于最新Spring 5.x,详细介绍了Spring 事务源码,包括标签源码解析。
  • 基于最新Spring 5.x,详细介绍了Spring 事务源码,包括TransactionInterceptor事务拦截器与事务的AOP增强实现的总体流程。
  • Spring事务传播Demo.zip

    2019-06-11 10:53:48
    参考博客https://blog.csdn.net/qq_42192693/article/details/91359997,用到的模型
  • spring事务源码分析

    2018-06-11 09:39:09
    spring的核心就是IC依赖注入,那么就要先解析依赖配置,然后再注入。所以spring的功能都会出现两块,一块是解析mxl,一块是构建BeanDefinition。...事务增强器也是这样,先要解析事务的标签,然后才是执行事务
  • NULL 博文链接:https://yizhenn.iteye.com/blog/2293339
  • Spring声明式事务管理源码解析

    千次阅读 2018-08-11 12:39:43
    1. PlatformTransactionManager:事务管理器顶级接口:各持久化框架要想接入Spring事务管理,必须自行提供该接口实现 2. TransactionDefinition:事务的属性顶级接口:其实现类封装事务隔离级别、事务传播性、...
  • 1、掌握Spring JDBC的配置; 2、掌握JdbcTemplae类中增删改查方法的使用;...3、了解Spring事务管理的3个核心接口; 4、了解Spring事务管理的两种方式; 5、掌握基于XML和Annotation的声明式事务管理的使用。
  • 其中编程式事务因为对代码入侵较大所以不被推荐使用,注解和aop切面的方式可以基于需求自行选择,我们以注解的方式为例来分析Spring事务的原理和源码实现。 首先我们简单看一下Spring事务的使用方式,配置: ...
  • ”关注我哟 好看记得加个“星标”哈! 前言 ...Spring事务应用大纲 在看这篇文章,以及下篇源码分析的文章我希望你对Spring AOP以及有充分的了解,不然一些细节问题你可能看不明白,关于Spring AOP如果
  • NULL 博文链接:https://tywo45.iteye.com/blog/267836
  • Spring源代码解析(六):Spring声明式事务处理.doc

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 119,433
精华内容 47,773
关键字:

spring事务源码

spring 订阅