• 作者简介:咱们好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主
  • 系列专栏:Java规划模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列
  • 假如感觉博主的文章还不错的话,请三连支撑一下博主哦
  • 博主正在努力完结2023计划中:以梦为马,扬帆起航,2023追梦人
  • 联系办法:hls1793929520,加我进群,咱们一同学习,一同前进

Spring 业务源码解析

一、引言

关于Java开发者而言,关于 Spring ,咱们一般作为黑盒来进行运用,不需求去翻开这个黑盒。

但随着目前程序员行业的开展,咱们有必要翻开这个黑盒,去探索其中的奥妙。

本期 Spring 源码解析系列文章,将带你领会 Spring 源码的奥妙

本期源码文章吸收了之前 Kafka 源码文章的错误,将不再一行一行的带咱们剖析源码,咱们将一些不重要的部分作为黑盒处理,以便咱们更快、更有效的阅读源码。

废话不多说,发车!

本篇目录如下:

从源码分析 Spring 事务的来龙去脉

本文流程图可重视大众号:爱敲代码的小黄,回复:业务 获取 交心的小黄为咱们预备的文件格局为 POS文件,便利咱们直接导入 ProcessOn 修改运用

二、业务的本质

  数据库业务(Database Transaction) ,是指作为单个逻辑作业单元履行的一系列操作,要么彻底地履行,要么彻底地不履行。

  业务处理能够保证除非业务性单元内的所有操作都成功完结,不然不会永久更新面向数据的资源。经过将一组相关操作组合为一个要么悉数成功要么悉数失败的单元,能够简化错误康复并使应用程序愈加牢靠。

  一个逻辑作业单元要成为业务,有必要满意所谓的 ACID原子性、一致性、阻隔性和持久性)特点。业务是数据库运转中的逻辑作业单位,由DBMS中的业务管理子系统担任业务的处理。

从源码分析 Spring 事务的来龙去脉

1、JDBC的业务

咱们来看一下在 JDBC 中对业务的操作处理:

public class JDBCTransactionExample {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstmt1 = null;
        PreparedStatement pstmt2 = null;
        try {
            // 加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 获取衔接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
            // 封闭主动提交,敞开业务
            conn.setAutoCommit(false);
            // 创立SQL句子
            String sql1 = "UPDATE account SET balance = balance - ? WHERE id = ?";
            String sql2 = "UPDATE account SET balance = balance + ? WHERE id = ?";
            // 创立PreparedStatement方针
            pstmt1 = conn.prepareStatement(sql1);
            pstmt2 = conn.prepareStatement(sql2);
            // 设置参数
            pstmt1.setDouble(1, 1000);
            pstmt1.setInt(2, 1);
            pstmt2.setDouble(1, 1000);
            pstmt2.setInt(2, 2);
            // 履行更新操作
            int count1 = pstmt1.executeUpdate();
            int count2 = pstmt2.executeUpdate();
            if (count1 > 0 && count2 > 0) {
                System.out.println("转账成功");
                // 提交业务
                conn.commit();
            } else {
                System.out.println("转账失败");
                // 回滚业务
                conn.rollback();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            try {
                if (conn != null) {
                    // 回滚业务
                    conn.rollback();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            try {
                if (pstmt1 != null) {
                    pstmt1.close();
                }
                if (pstmt2 != null) {
                    pstmt2.close();
                }
                if (conn != null) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

上面的代码,我信任大部分的人都应该接触过,这儿也就不多说了

首要咱们看几个要点过程:

  • 获取衔接:Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password")
  • 封闭主动提交,敞开业务:conn.setAutoCommit(false)
  • 提交业务:conn.commit()
  • 回滚业务:conn.rollback()

2、Spring的业务

咱们在日常生产项目中,项目由 ControllerSerivceDao 三层进行构建。

从源码分析 Spring 事务的来龙去脉

咱们从上图中能够了解到:

关于 addUser 办法实践关于数据调用来说,别离调用了 insertUser()insertLog 办法,对数据库的操作为两次

咱们要保证 addUser 办法是契合业务界说的。

2.1 xml装备

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
	<!-- 敞开扫描 -->
	<context:component-scan base-package="com.dpb.*"></context:component-scan>
	<!-- 装备数据源 -->
	<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="username" value="pms"/>
		<property name="password" value="pms"/>
	</bean>
	<!-- 装备JdbcTemplate -->
	<bean class="org.springframework.jdbc.core.JdbcTemplate" >
		<constructor-arg name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 
	Spring中,运用XML装备业务三大过程:  
		1. 创立业务管理器  
		2. 装备业务办法  
		3. 装备AOP
	 -->
	 <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
	 	<property name="dataSource" ref="dataSource"/>
	 </bean>
	 <tx:advice id="advice" transaction-manager="transactionManager">
	 	<tx:attributes>
	 		<tx:method name="fun*" propagation="REQUIRED"/>
	 	</tx:attributes>
	 </tx:advice>
	 <!-- aop装备 -->
	 <aop:config>
		 <aop:pointcut expression="execution(* *..service.*.*(..))" id="tx"/>
	 	 <aop:advisor advice-ref="advice" pointcut-ref="tx"/>
	 </aop:config>
</beans>

2.2 注解装备

首先有必要要增加 @EnableTransactionManagement 注解,保证业务注解收效

@EnableTransactionManagement
public class AnnotationMain {
    public static void main(String[] args) {
    }
}

其次,在办法上增加 @Transactional 代表注解收效

@Transactional
public int insertUser(User user) {
    userDao.insertUser();
    userDao.insertLog();
    return 1;
}

上面的操作触及两个要点:

  • 业务的传达特点

  • 业务的阻隔等级

三、Spring业务源码剖析

本次剖析源码咱们会尽量挑要点来讲,因为业务源码自身便是依托 AOP 完结的,咱们之前已经很具体的讲过 IOCAOP 的源码完结了,这次带咱们一同过一遍业务即可。

因为从博主自身而言,我感觉 Spring 业务其实没有那么的重要,面试也不常考,所以不会花大量的时刻去剖析细节源码。

1、TransactionManager

首先咱们看一下这个接口的一些组成装备:

从源码分析 Spring 事务的来龙去脉
****

这儿咱们要点看 PlatformTransactionManager 的完结,其完结总共三个办法:

  • 获取业务:TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
  • 提交业务:void commit(TransactionStatus status)
  • 回滚业务:void rollback(TransactionStatus status)

咱们别离看一下其怎么完结的

1.1 获取业务

咱们想一下,在获取业务这一阶段,咱们会做什么功用呢?

参阅上述咱们 JDBC 的过程,这个阶段应该会 创立衔接并且敞开业务

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition){
   // PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED都需求新建业务
   if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
         def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
         def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      //没有当时业务的话,REQUIRED,REQUIRES_NEW,NESTED挂起的是空业务,然后创立一个新业务
      SuspendedResourcesHolder suspendedResources = suspend(null);
      try {
         // 看这儿要点:开始业务
         return startTransaction(def, transaction, debugEnabled, suspendedResources);
      }
      catch (RuntimeException | Error ex) {
         // 康复挂起的业务
         resume(null, suspendedResources);
         throw ex;
      }
   }
}
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
    // 是否需求新同步
	 boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
	 // 创立新的业务
	 DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
	// 【要点】敞开业务和衔接
	doBegin(transaction, definition);
	// 新同步业务的设置,针关于当时线程的设置
	prepareSynchronization(status, definition);
	return status;
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
    		// 判断业务方针没有数据库衔接持有器
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				// 【要点】经过数据源获取一个数据库衔接方针
				Connection newCon = obtainDataSource().getConnection();
				// 把咱们的数据库衔接包装成一个ConnectionHolder方针 然后设置到咱们的txObject方针中去
             // 再次进来时,该 txObject 就已经有业务装备了
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}
    		// 【要点】获取衔接
    		con = txObject.getConnectionHolder().getConnection();
			// 为当时的业务设置阻隔等级【数据库的阻隔等级】
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			// 设置先前阻隔等级
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			// 设置是否只读
			txObject.setReadOnly(definition.isReadOnly());
			// 封闭主动提交
			if (con.getAutoCommit()) {
				//设置需求康复主动提交
				txObject.setMustRestoreAutoCommit(true);
				// 【要点】封闭主动提交
				con.setAutoCommit(false);
			}
			// 判断业务是否需求设置为只读业务
			prepareTransactionalConnection(con, definition);
			// 标记激活业务
			txObject.getConnectionHolder().setTransactionActive(true);
			// 设置业务超时时刻
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}
			// 绑定咱们的数据源和衔接到咱们的同步管理器上,把数据源作为key,数据库衔接作为value 设置到线程变量中
			if (txObject.isNewConnectionHolder()) {
				// 将当时获取到的衔接绑定到当时线程
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}
}

到这儿,咱们的 获取业务 接口完结了 数据库衔接的创立封闭主动提交(敞开业务),将 Connection 注册到了缓存(resources)傍边,便于获取。

1.2 提交业务

public final void commit(TransactionStatus status) throws TransactionException {
		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		// 假如在业务链中已经被标记回滚,那么不会测验提交业务,直接回滚
		if (defStatus.isLocalRollbackOnly()) {
			// 不可预期的回滚
			processRollback(defStatus, false);
			return;
		}
		// 设置了大局回滚
		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			// 可预期的回滚,或许会报反常
			processRollback(defStatus, true);
			return;
		}
		// 【要点】处理业务提交
		processCommit(defStatus);
}
// 处理提交,先处理保存点,然后处理新业务,假如不是新业务不会真实提交,要等外层是新业务的才提交,
// 最后依据条件履行数据铲除,线程的私有资源解绑,重置衔接主动提交,阻隔等级,是否只读,开释衔接,康复挂起业务等
private void processCommit(DefaultTransactionStatus status) throws TransactionException {;
     // 假如是独立的业务则直接提交
	  doCommit(status);
                                                                             //依据条件,完结后数据铲除,和线程的私有资源解绑,重置衔接主动提交,阻隔等级,是否只读,开释衔接,康复挂起业务等
	  cleanupAfterCompletion(status);
}

这儿比较重要的有两个过程:

  • doCommit:提交业务(直接运用 JDBC 提交即可)

    protected void doCommit(DefaultTransactionStatus status) {
       DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
       Connection con = txObject.getConnectionHolder().getConnection();
       try {
          // JDBC衔接提交
          con.commit();
       }
       catch (SQLException ex) {
          throw new TransactionSystemException("Could not commit JDBC transaction", ex);
       }
    }
    
  • cleanupAfterCompletion:数据铲除,与线程中的私有资源解绑,便利开释

    // 线程同步状况铲除
    TransactionSynchronizationManager.clear();
    // 铲除同步状况【这些都是线程的缓存,运用ThreadLocal的】
    public static void clear() {
        synchronizations.remove();
        currentTransactionName.remove();
        currentTransactionReadOnly.remove();
        currentTransactionIsolationLevel.remove();
        actualTransactionActive.remove();
    }
    // 假如是新业务的话,进行数据铲除,线程的私有资源解绑,重置衔接主动提交,阻隔等级,是否只读,开释衔接等
    doCleanupAfterCompletion(status.getTransaction());
    // 此办法做铲除衔接相关操作,比方重置主动提交啊,只读特点啊,解绑数据源啊,开释衔接啊,铲除链接持有器特点
    protected void doCleanupAfterCompletion(Object transaction) {
    		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    		// 将数据库衔接从当时线程中免除绑定
    		TransactionSynchronizationManager.unbindResource(obtainDataSource());
    		// 开释衔接
    		Connection con = txObject.getConnectionHolder().getConnection();
    		// 康复数据库衔接的主动提交特点
    		con.setAutoCommit(true);
          // 重置数据库衔接
    	   DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
    		// 假如当时业务是独立的新创立的业务则在业务完结时开释数据库衔接
    		DataSourceUtils.releaseConnection(con, this.dataSource);
    		// 衔接持有器特点铲除
    		txObject.getConnectionHolder().clear();
    	}
    

这便是咱们提交业务的操作了,总之来说,首要便是 调用JDBC的commit提交铲除一系列的线程内部数据和装备

1.3 回滚业务

public final void rollback(TransactionStatus status) throws TransactionException {
   DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
   processRollback(defStatus, false);
}
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
	 // 回滚的擦欧洲哦
    doRollback(status);
    // 回滚完结后回调
    triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
	 // 依据业务状况信息,完结后数据铲除,和线程的私有资源解绑,重置衔接主动提交,阻隔等级,是否只读,开释衔接,康复挂起业务等
	cleanupAfterCompletion(status);
}
protected void doRollback(DefaultTransactionStatus status) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
		Connection con = txObject.getConnectionHolder().getConnection();
		// jdbc的回滚
		con.rollback();
}

回滚业务,简略来说 调用JDBC的rollback铲除数据

2、 业务AOP的完结

咱们来考虑一下,使用 TransactionManager 重写一下咱们第一步的 JDBC 的功用

@Autowired
	private UserDao userDao;
	@Autowired
	private PlatformTransactionManager txManager;
	@Autowired
	private LogService logService;
	@Transactional
	public void insertUser(User u) {
		// 1、创立业务界说
		DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
		// 2、依据界说敞开业务
		TransactionStatus status = txManager.getTransaction(definition);
		try {
			this.userDao.insert(u);
			Log log = new Log(System.currentTimeMillis() + "", System.currentTimeMillis() + "-" + u.getUserName());
			// this.doAddUser(u);
			this.logService.insertLog(log);
			// 3、提交业务
			txManager.commit(status);
		} catch (Exception e) {
			// 4、反常了,回滚业务
			txManager.rollback(status);
			throw e;
		}
	}

咱们看到上述代码及考虑一下 AOP 的效果和源码,有没有一丝丝想法

比方我现在是面试官,问你一个问题:你怎么去规划 Spring 的业务

假如一点点想法都没有的话,也不必着急,咱们来慢慢的剖析

2.1 为什么运用AOP?

咱们想,假如咱们要完结业务,在每一个办法里面都需求进行以下三个过程:

  • 获取业务
  • 提交业务
  • 回滚业务

是不是显得咱们的代码很臃肿,那么咱们能不能把这三个过程搞成一个通用化的东西

一些代码在办法前履行,一些代码办法后履行

这个时分,你是不是就想到了 AOP(切面编程)了

当然,Spring 中也是如此做的,使用 AOP 来对业务进行了统一的包装完结

2.2 @EnableTransactionManagement

咱们知道了运用 AOP 技能完结,那到底是怎么完结的呢?

咱们从 @EnableTransactionManagement 注解聊起,咱们点进该注解:

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

很明显,TransactionManagementConfigurationSelector 类是咱们首要重视的内容

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
   /**
    * 此处是AdviceMode的效果,默认是用署理,另外一个是ASPECTJ
    */
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY:
            return new String[] {AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ:
            return new String[] {determineTransactionAspectClass()};
         default:
            return null;
      }
   }
}

总共注册了两个:

  • AutoProxyRegistrar.class:注册AOP处理器

  • ProxyTransactionManagementConfiguration.class:署理业务装备,注册业务需求用的一些类,而且Role=ROLE_INFRASTRUCTURE都是归于内部等级的

    @Configuration(proxyBeanMethods = false)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
       @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
       @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
       public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
             TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
    		// 【要点】注册了 BeanFactoryTransactionAttributeSourceAdvisor 的 advisor
           // 其 advice 为 transactionInterceptor
          BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
          advisor.setTransactionAttributeSource(transactionAttributeSource);
          advisor.setAdvice(transactionInterceptor);
          if (this.enableTx != null) {
             advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
          }
          return advisor;
       }
       @Bean
       @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
       public TransactionAttributeSource transactionAttributeSource() {
          return new AnnotationTransactionAttributeSource();
       }
       @Bean
       @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
       public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
          TransactionInterceptor interceptor = new TransactionInterceptor();
          interceptor.setTransactionAttributeSource(transactionAttributeSource);
          if (this.txManager != null) {
             interceptor.setTransactionManager(this.txManager);
          }
          return interceptor;
       }
    }
    

    到这儿,看到 BeanFactoryTransactionAttributeSourceAdvisoradvisor 结束的类,AOPDNA 应该动了,其 advicetransactionInterceptor

    到这儿,咱们考虑一下,使用咱们之前学习到的 AOP 的源码,猜想其运转逻辑:

    • 咱们在办法上写上 @EnableTransactionManagement 注解,Spring 会注册一个 BeanFactoryTransactionAttributeSourceAdvisor 的类
    • 创立对应的办法 Bean 时,会和 AOP 相同,使用该 Advisor 类生成对应的署理方针
    • 终究调用办法时,会调用署理方针,并经过盘绕增强来达到业务的功用

2.3 TransactionInterceptor

咱们从上面看到其 advice 正是 TransactionInterceptor,那自然不必多说

从上篇 AOP 得知,署理方针运转时,会拿到所有的 advice 并进行排序,职责链递归运转

所以,咱们直接看 TransactionInterceptor 这个类即可

这儿先看一下 TransactionInterceptor 类图

从源码分析 Spring 事务的来龙去脉

然后看其源码内容:

这儿的 invoke 办法怎么履行到的,我就不多介绍了,看过上篇 AOP 的文章应该都懂,不熟悉的小伙伴能够去看一下

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor {
   @Override
	@Nullable
	public Object invoke(MethodInvocation invocation) throws Throwable {
		// 获取咱们的署理方针的class特点
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		/**
		 * 以业务的办法调用方针办法
		 * 在这埋了一个钩子函数 用来回调方针办法的
		 */
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
}
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation){
	   // 获取咱们的业务特点源方针
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 经过业务特点源方针获取到当时办法的业务特点信息
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 获取咱们装备的业务管理器方针
		final TransactionManager tm = determineTransactionManager(txAttr);
    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
        // 【要点】创立TransactionInfo
		  TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
        try {
				// 履行被增强办法,调用具体的处理逻辑【咱们实践的办法】
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// 反常回滚
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				//铲除业务信息,康复线程私有的老的业务信息
				cleanupTransactionInfo(txInfo);
			}
        //成功后提交,会进行资源储量,衔接开释,康复挂起业务等操作
		  commitTransactionAfterReturning(txInfo);
		return retVal;
    }
}
// 创立衔接 + 敞开业务
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
    // 获取TransactionStatus业务状况信息
    status = tm.getTransaction(txAttr);
    // 依据指定的特点与status预备一个TransactionInfo,
	return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
// 存在反常时回滚业务
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    // 进行回滚
    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
// 调用业务管理器的提交办法
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo){
    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}

然后..没有然后了

业务便是这样简略、朴实无华的完结了

2.4 XML装备

这儿略微讲下 xml 装备的,xml 也相同,在咱们进行 xml 文件解析的时分,将 BeanFactoryTransactionAttributeSourceAdvisor 拼装起来注册到 BeanDefinitionMap

这儿能够参阅上篇 AOP 的解析和生成

生成后也相同,调用的是署理办法,判断改办法有没有被署理,然后递归+职责链履行 Advice 即可

没什么困难的

四、流程图

咱们有没有感觉业务有点水,便是用了 Spring AOP 的功用包装了一下

根本的完结还是依托的 JDBC,但有一些不得不记的小知识点:业务的传达特点业务的阻隔等级

这两个关于装备的还是要去看一下,咱们本篇就不再多叙述了,网上很多材料都有的

咱们画一下根本的流程图

从源码分析 Spring 事务的来龙去脉

整个流程也相较于简略,有兴趣的能够去更细的看一下

五、总结

记住校招时分,当时对 Spring 懵懂无知,转眼间也被迫看了源码

本文首要从 JDBC 拼装业务过度到 Spring 的业务注解,终究经过 AOP 的技能去进行切面处理

经过这篇文章,我信任,99% 的人应该都能够理解了 Spring 业务 的来龙去脉

那么怎么证明你真的理解了 Spring 业务呢,我这儿出个经典的标题,咱们能够想一下:假如让你规划Spring中业务的流程,你会怎么规划?

假如你能看到这,那博主有必要要给你一个大大的鼓励,谢谢你的支撑!

喜爱的能够点个重视,后续会更新 Spring 循环依赖 的源码文章

我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,Java领域新星创作者,喜爱后端架构和中间件源码。