spring tx 事務核心流程源碼分析

今天我們來看下spring 的 tx 模塊的核心流程。

1. 實例

配置一個啓動事務管理類,配置一個數據源事務管理器:

	@Configuration
	@EnableTransactionManagement
	static class DefaultTxManagerNameConfig {

		@Bean
		PlatformTransactionManager transactionManager(DataSource dataSource) {
			return new DataSourceTransactionManager(dataSource);
		}
	}

配置一個數據源、JdbcFooRepository 類

	@Configuration
	static class Config {

		@Bean
		FooRepository fooRepository() {
			JdbcFooRepository repos = new JdbcFooRepository();
			repos.setDataSource(dataSource());
			return repos;
		}

		@Bean
		DataSource dataSource() {
			return new EmbeddedDatabaseBuilder()
				.setType(EmbeddedDatabaseType.HSQL)
				.build();
		}
	}

基礎的 DAO 類,在 findAll() 方法上標註 @Transactional 註解

	interface FooRepository {

		List<Object> findAll();
	}

	static class JdbcFooRepository implements FooRepository {

		public void setDataSource(DataSource dataSource) {
		}

		@Override
		@Transactional
		public List<Object> findAll() {
			ArrayList<Object> result = new ArrayList<>();
			for (int i1 = 0; i1 < 10; i1++) {
				int random = (int) (Math.random() * 100);
				result.add(random);
			}
			return result;
		}
	}

最後配置一個測試類:

public class EnableTransactionManagementIntegrationTests {
  
  @Test
	void repositoryIsTxProxy_withDefaultTxManagerName() {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class, DefaultTxManagerNameConfig.class);
		FooRepository repo = ctx.getBean(FooRepository.class);
		List<Object> all = repo.findAll();
		System.out.println("all = " + all);
	}

}

這樣就配置了一個使用事務註解支持事務的方法的例子了。

2. 分析

我們從 DefaultTxManagerNameConfig 上的 @EnableTransactionManagement 開始看:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

	/**
	 * 指定使用什麼代理模式(true 爲 cglib 代理,false 爲 jdk 代理)
	 *
	 * Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
	 * opposed to standard Java interface-based proxies ({@code false}). The default is
	 * {@code false}. <strong>Applicable only if {@link #mode()} is set to
	 * {@link AdviceMode#PROXY}</strong>.
	 * <p>Note that setting this attribute to {@code true} will affect <em>all</em>
	 * Spring-managed beans requiring proxying, not just those marked with
	 * {@code @Transactional}. For example, other beans marked with Spring's
	 * {@code @Async} annotation will be upgraded to subclass proxying at the same
	 * time. This approach has no negative impact in practice unless one is explicitly
	 * expecting one type of proxy vs another, e.g. in tests.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * 通知的模式,代理模式或者 aspectj,一般是使用代理模式。
	 * 注意代理模式只允許調用攔截,通過在本類中的本地調用不能被攔截;
	 * 一個 Transactional 註解在一個本地調用的方法上將會被 spring 的攔截器忽略,甚至不會再這種場景中出現。
	 * 對於攔截更多高級
	 *
	 * Indicate how transactional advice should be applied.
	 * <p><b>The default is {@link AdviceMode#PROXY}.</b>
	 * Please note that proxy mode allows for interception of calls through the proxy
	 * only. Local calls within the same class cannot get intercepted that way; an
	 * {@link Transactional} annotation on such a method within a local call will be
	 * ignored since Spring's interceptor does not even kick in for such a runtime
	 * scenario. For a more advanced mode of interception, consider switching this to
	 * {@link AdviceMode#ASPECTJ}.
	 */
	AdviceMode mode() default AdviceMode.PROXY;

	/**
	 * Indicate the ordering of the execution of the transaction advisor
	 * when multiple advices are applied at a specific joinpoint.
	 * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
	 */
	int order() default Ordered.LOWEST_PRECEDENCE;

}

這個類有三個屬性,proxyTargetClass、mode、order,分別表示:是否使用 cglib 代理、通知的模式(PROXY 或者 ASPECTJ)、排序。

它還使用了 @Import(TransactionManagementConfigurationSelector.class) 註解,導入了 TransactionManagementConfigurationSelector 類:

/**
 * 在導入 @Configuration 註解類時候,根據選擇 EnableTransactionManagement 的 mode,來選擇
 * AbstractTransactionManagementConfiguration 類合適的子類,
 *
 * Selects which implementation of {@link AbstractTransactionManagementConfiguration}
 * should be used based on the value of {@link EnableTransactionManagement#mode} on the
 * importing {@code @Configuration} class.
 *
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 * @see EnableTransactionManagement
 * @see ProxyTransactionManagementConfiguration
 * @see TransactionManagementConfigUtils#TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
 * @see TransactionManagementConfigUtils#JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
 */
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	/**
	 * Returns {@link ProxyTransactionManagementConfiguration} or
	 * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
	 * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
	 * respectively.
	 */
	@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;
		}
	}

	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}

}

看下它的類圖結構:

TransactionManagementConfigurationSelector

這個類繼承了 AdviceModeImportSelector 類,它是一個 ImportSelector 導入選擇器,重寫了 selectImports() 方法,通過 adviceMode 來返回一組類的名稱,我們一般使用 AdviceMode.PROXY,可以看到它會返回 AutoProxyRegistrar.classs 和 ProxyTransactionManagementConfiguration.class 這兩個類的名稱。

我們回顧下 ImportSelector 類,它的 selectImports() 方法是在 org.springframework.context.annotation.ConfigurationClassParser#processImports 中進行調用的。它是在 spring 容器啓動時,執行 bean 工廠註冊器後置處理器時,調用了 ConfigurationClassParser 配置類解析器的解析掃描 @Configuration 註解的類的 bean 定義流程中執行的。

2.1 AutoProxyRegistrar

接着繼續看 AutoProxyRegistrar.classs 這個類,它的類圖:

AutoProxyRegistrar

它實現爲:

/**
 * 針對當前的 BeanDefinitionRegistry 作爲一個合適的基於 @Enable* 註解標有 mode 和 proxyTargetClass 的屬性,
 * 設置到正確的值。
 *
 * Registers an auto proxy creator against the current {@link BeanDefinitionRegistry}
 * as appropriate based on an {@code @Enable*} annotation having {@code mode} and
 * {@code proxyTargetClass} attributes set to the correct values.
 *
 * @author Chris Beams
 * @since 3.1
 * @see org.springframework.cache.annotation.EnableCaching
 * @see org.springframework.transaction.annotation.EnableTransactionManagement
 */
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	private final Log logger = LogFactory.getLog(getClass());

	/**
	 * 註冊bean 定義
	 *
	 * Register, escalate, and configure the standard auto proxy creator (APC) against the
	 * given registry. Works by finding the nearest annotation declared on the importing
	 * {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass}
	 * attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
	 * {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
	 * subclass (CGLIB) proxying.
	 * <p>Several {@code @Enable*} annotations expose both {@code mode} and
	 * {@code proxyTargetClass} attributes. It is important to note that most of these
	 * capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
	 * single APC}. For this reason, this implementation doesn't "care" exactly which
	 * annotation it finds -- as long as it exposes the right {@code mode} and
	 * {@code proxyTargetClass} attributes, the APC can be registered and configured all
	 * the same.
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			// 獲取模式
			Object mode = candidate.get("mode");
			// 獲取代理目標類
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				// 使用代理模式
				if (mode == AdviceMode.PROXY) {
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						// 強制自動代理創建器使用類代理,proxyTargetClass
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
		if (!candidateFound && logger.isInfoEnabled()) {
			String name = getClass().getSimpleName();
			logger.info(String.format("%s was imported but no annotations were found " +
					"having both 'mode' and 'proxyTargetClass' attributes of type " +
					"AdviceMode and boolean respectively. This means that auto proxy " +
					"creator registration and configuration may not have occurred as " +
					"intended, and components may not be proxied as expected. Check to " +
					"ensure that %s has been @Import'ed on the same class where these " +
					"annotations are declared; otherwise remove the import of %s " +
					"altogether.", name, name, name));
		}
	}

}

它是一個 ImportBeanDefinitionRegistrar 類型,導入 bean 定義註冊器,實現了 registerBeanDefinitions() 方法,這個方法做的事情:

  1. 獲取導入類的註解元數據;
  2. 獲取 mode 註解屬性、proxyTargetClass 註解屬性;
  3. 根據它們的值,註冊一個名稱爲 org.springframework.aop.config.internalAutoProxyCreator,值爲 InfrastructureAdvisorAutoProxyCreator 類型的 bean 定義;
  4. 以及bean 定義的 proxyTargetClass 屬性。

它的這個方法是在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars 處調用的,也是屬於配置類後置處理器註冊已經將 bean 定義解析爲配置類的流程中。

2.2 InfrastructureAdvisorAutoProxyCreator

看下 InfrastructureAdvisorAutoProxyCreator 類,它的類圖:

InfrastructureAdvisorAutoProxyCreator

它的實現:

/**
 * 自動代理創建器,僅僅考慮基礎的增強器 beans,忽略其他應用程序定義的增強器
 *
 * Auto-proxy creator that considers infrastructure Advisor beans only,
 * ignoring any application-defined Advisors.
 *
 * @author Juergen Hoeller
 * @since 2.0.7
 */
@SuppressWarnings("serial")
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

	@Nullable
	private ConfigurableListableBeanFactory beanFactory;


	@Override
	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		super.initBeanFactory(beanFactory);
		this.beanFactory = beanFactory;
	}

	@Override
	protected boolean isEligibleAdvisorBean(String beanName) {
		// 判斷是否是一個合格的增強器,@Role(BeanDefinition.ROLE_INFRASTRUCTURE) bean 定義的角色是基礎類
		return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
				this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
	}

}

這個類它和 spring aop 中的 AnnotationAwareAspectJAutoProxyCreator 類很像,沒錯!它們都是共同繼承了 AbstractAdvisorAutoProxyCreator 類型,間接的實現了 BeanPostProcessor 的 postProcessBeforeInstantiation() 方法和 postProcessAfterInitialization() 方法。這兩個方法主要是對代理對象進行檢查以及初始化,並且進行創建其代理。

2.3 ProxyTransactionManagementConfiguration

再看下 ProxyTransactionManagementConfiguration 類:

/**
 * 這是一個 @Configuration 類,它註冊了 spring 基礎類,這些類時啓動基於代理的註解驅動的事務管理器的必要類。
 *
 * {@code @Configuration} class that registers the Spring infrastructure beans
 * necessary to enable proxy-based annotation-driven transaction management.
 *
 * @author Chris Beams
 * @author Sebastien Deleuze
 * @since 3.1
 * @see EnableTransactionManagement
 * @see TransactionManagementConfigurationSelector
 */
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	/**
	 * 註冊一個內部的事務增強器 org.springframework.transaction.config.internalTransactionAdvisor
	 *
	 * @param transactionAttributeSource
	 * @param transactionInterceptor
	 * @return
	 */
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		// 設置事務屬性源
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		// 設置通知事務攔截器
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	/**
	 * 定義一個註解事務屬性源
	 *
	 * @return
	 */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		// 註解的事務屬性源
		return new AnnotationTransactionAttributeSource();
	}

	/**
	 * 定義一個事務攔截器
	 *
	 * @param transactionAttributeSource
	 * @return
	 */
	@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;
	}

}

這個類引入了三個 bean:AnnotationTransactionAttributeSource、TransactionInterceptor、BeanFactoryTransactionAttributeSourceAdvisor。

2.4 AnnotationTransactionAttributeSource

它是一個註解事務屬性源,看下它的類圖:

AnnotationTransactionAttributeSource

它的實現:

/**
 * Implementation of the
 * {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
 * interface for working with transaction metadata in JDK 1.5+ annotation format.
 *
 * <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
 * exposes corresponding transaction attributes to Spring's transaction infrastructure.
 * Also supports JTA 1.2's {@link javax.transaction.Transactional} and EJB3's
 * {@link javax.ejb.TransactionAttribute} annotation (if present).
 * This class may also serve as base class for a custom TransactionAttributeSource,
 * or get customized through {@link TransactionAnnotationParser} strategies.
 *
 * @author Colin Sampaleanu
 * @author Juergen Hoeller
 * @since 1.2
 * @see Transactional
 * @see TransactionAnnotationParser
 * @see SpringTransactionAnnotationParser
 * @see Ejb3TransactionAnnotationParser
 * @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource
 * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource
 */
@SuppressWarnings("serial")
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {

	private static final boolean jta12Present;

	private static final boolean ejb3Present;

	static {
		ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
		jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
		ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
	}

	private final boolean publicMethodsOnly;

	private final Set<TransactionAnnotationParser> annotationParsers;


	/**
	 * Create a default AnnotationTransactionAttributeSource, supporting
	 * public methods that carry the {@code Transactional} annotation
	 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
	 */
	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource, supporting
	 * public methods that carry the {@code Transactional} annotation
	 * or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
	 * @param publicMethodsOnly whether to support public methods that carry
	 * the {@code Transactional} annotation only (typically for use
	 * with proxy-based AOP), or protected/private methods as well
	 * (typically used with AspectJ class weaving)
	 */
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		if (jta12Present || ejb3Present) {
			this.annotationParsers = new LinkedHashSet<>(4);
			this.annotationParsers.add(new SpringTransactionAnnotationParser());
			if (jta12Present) {
				this.annotationParsers.add(new JtaTransactionAnnotationParser());
			}
			if (ejb3Present) {
				this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
			}
		}
		else {
			this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
		}
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource.
	 * @param annotationParser the TransactionAnnotationParser to use
	 */
	public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {
		this.publicMethodsOnly = true;
		Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null");
		this.annotationParsers = Collections.singleton(annotationParser);
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource.
	 * @param annotationParsers the TransactionAnnotationParsers to use
	 */
	public AnnotationTransactionAttributeSource(TransactionAnnotationParser... annotationParsers) {
		this.publicMethodsOnly = true;
		Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
		this.annotationParsers = new LinkedHashSet<>(Arrays.asList(annotationParsers));
	}

	/**
	 * Create a custom AnnotationTransactionAttributeSource.
	 * @param annotationParsers the TransactionAnnotationParsers to use
	 */
	public AnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {
		this.publicMethodsOnly = true;
		Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
		this.annotationParsers = annotationParsers;
	}


	@Override
	public boolean isCandidateClass(Class<?> targetClass) {
		for (TransactionAnnotationParser parser : this.annotationParsers) {
			if (parser.isCandidateClass(targetClass)) {
				return true;
			}
		}
		return false;
	}

	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
		// 從類上找事務屬性
		return determineTransactionAttribute(clazz);
	}

	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Method method) {
		// 從方法上找事務屬性
		return determineTransactionAttribute(method);
	}

	/**
	 * Determine the transaction attribute for the given method or class.
	 * <p>This implementation delegates to configured
	 * {@link TransactionAnnotationParser TransactionAnnotationParsers}
	 * for parsing known annotations into Spring's metadata attribute class.
	 * Returns {@code null} if it's not transactional.
	 * <p>Can be overridden to support custom annotations that carry transaction metadata.
	 * @param element the annotated method or class
	 * @return the configured transaction attribute, or {@code null} if none was found
	 */
	@Nullable
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		// 遍歷所有的註解解析器
		for (TransactionAnnotationParser parser : this.annotationParsers) {
			// 從事務註解解析器上解析
			TransactionAttribute attr = parser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}

	/**
	 * By default, only public methods can be made transactional.
	 */
	@Override
	protected boolean allowPublicMethodsOnly() {
		return this.publicMethodsOnly;
	}


	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof AnnotationTransactionAttributeSource)) {
			return false;
		}
		AnnotationTransactionAttributeSource otherTas = (AnnotationTransactionAttributeSource) other;
		return (this.annotationParsers.equals(otherTas.annotationParsers) &&
				this.publicMethodsOnly == otherTas.publicMethodsOnly);
	}

	@Override
	public int hashCode() {
		return this.annotationParsers.hashCode();
	}

}

這個類間接的實現了 TransactionAttributeSource 接口,間接的實現了它的 org.springframework.transaction.interceptor.TransactionAttributeSource#isCandidateClass 和 org.springframework.transaction.interceptor.TransactionAttributeSource#getTransactionAttribute 方法,這兩個方法都是在 org.springframework.aop.support.AopUtils#canApply 這個方法中被調用的,AopUtils#canApply 方法又是在上面提到的實現了 BeanPostProcessor 接口的 postProcessAfterInitialization() 方法的 InfrastructureAdvisorAutoProxyCreator 類所實現。

2.4.1 判斷是否候選類 isCandidateClass()

isCandidateClass() 方法:它在 bean 初始化之後,在獲取通知和增強器的方法邏輯 getAdvicesAndAdvisorsForBean() 中調用 findAdvisorsThatCanApply(),再調用 canApply() 方法,根據 BeanFactoryTransactionAttributeSourceAdvisor 增強器,獲取事務屬性源切點 BeanFactoryTransactionAttributeSourceAdvisor#pointcut TransactionAttributeSourcePointcut 類型,獲取切點 AnnotationTransactionAttributeSource 類,間接的調用它的 isCandidateClass() 方法,最後調用 SpringTransactionAnnotationParser 的 isCandidateClass() 方法,由 AnnotationUtils 工具類判斷目標類是否有 @Transactional 來判斷是否符合合格的類;

2.4.2 獲取事務屬性 TransactionAttribute 類型 getTransactionAttribute()

它實現 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute:

	/**
	 * 爲這個方法執行獲取事務屬性。如果方法屬性沒有找到,默認是爲類的事務屬性。
	 *
	 * Determine the transaction attribute for this method invocation.
	 * <p>Defaults to the class's transaction attribute if no method attribute is found.
	 * @param method the method for the current invocation (never {@code null})
	 * @param targetClass the target class for this invocation (may be {@code null})
	 * @return a TransactionAttribute for this method, or {@code null} if the method
	 * is not transactional
	 */
	@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// 首先,從緩存中找
		// First, see if we have a cached value.
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		else {
			// 計算事務屬性
			// We need to work it out.
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			if (txAttr == null) {
				// 在緩存中標識事務屬性爲空
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				// 爲事務屬性設置方法描述符
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
					DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
					dta.setDescriptor(methodIdentification);
					dta.resolveAttributeStrings(this.embeddedValueResolver);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				// 加入到緩存
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}


	/**
	 * Determine a cache key for the given method and target class.
	 * <p>Must not produce same key for overloaded methods.
	 * Must produce same key for different instances of the same method.
	 * @param method the method (never {@code null})
	 * @param targetClass the target class (may be {@code null})
	 * @return the cache key (never {@code null})
	 */
	protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
		return new MethodClassKey(method, targetClass);
	}

	/**
	 * 計算屬性源
	 *
	 * Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
	 * {@link #getTransactionAttribute} is effectively a caching decorator for this method.
	 * <p>As of 4.1.8, this method can be overridden.
	 * @since 4.1.8
	 * @see #getTransactionAttribute
	 */
	@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 不允許非 public 修飾的方法
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// 方法可能在接口上,但是我們需要從目標類上獲取屬性。
		// 如果目標類是空,該方法將保持不變
		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// 首先嚐試的是目標類上的方法
		// First try is the method in the target class.
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}

		// 然後嘗試的是在方法所在的類上
		// Second try is the transaction attribute on the target class.
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}

		if (specificMethod != method) {
			// 從方法上找
			// Fallback is to look at the original method.
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// 最後在方法所在的接口上找
			// Last fallback is the class of the original method.
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}

		return null;
	}

getTransactionAttribute() 方法:也是在上述 isCandidateClass() 方法調用邏輯中的 org.springframework.aop.support.AopUtils#canApply 方法中,通過 TransactionAttributeSourcePointcut 類調用 matches() 方法,再調用 getTransactionAttributeSource() 方法獲取事務屬性源,最後獲取事務屬性 TransactionAttribute。它主要是在 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 這個方法中實現的邏輯:

  1. 先從緩存中查找事務屬性;
  2. 計算事務屬性 computeTransactionAttribute();
    1. 判斷方法是否是 public 修飾的;
    2. 獲取目標方法;
    3. 先從目標類上的方法查找 @Transcation 註解;
    4. 然後嘗試從目標方法所在類上查找 @Transcation 註解;
    5. 在從接口的方法上查找 @Transcation 註解;
    6. 最後再從接口類上的查找 @Transcation 註解;
  3. 保存到緩存。

2.4.3 查找事務屬性 findTransactionAttribute()

這個方法是一個重載方法,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.Class<?>)org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method),最終都調用到了 org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute 方法:

	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		// 遍歷所有的註解解析器
		for (TransactionAnnotationParser parser : this.annotationParsers) {
			// 從事務註解解析器上解析
			TransactionAttribute attr = parser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}

它通過事務註解解析器來解析:org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

	@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		// 解析 @Transactional 註解
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			// 真正的開始解析
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	/**
	 * 開始解析事務註解
	 *
	 * @param attributes
	 * @return
	 */
	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());
		String timeoutString = attributes.getString("timeoutString");
		Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
				"Specify 'timeout' or 'timeoutString', not both");
		rbta.setTimeoutString(timeoutString);

		// 是否只讀
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		// 事務名稱
		rbta.setQualifier(attributes.getString("value"));
		rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));

		// 回滾規則
		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		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;
	}

可以看到它最終會返回一個 RuleBasedTransactionAttribute 類型的事務屬性。

2.4.4 事務定義 RuleBasedTransactionAttribute

它的類圖:

RuleBasedTransactionAttribute

這個類實現了 TransactionDefinition 接口,我們看下這個接口類圖是:

TransactionDefinition

這個類主要定義了事務的一些基本屬性信息,有事務名稱、事務傳播行爲、事務隔離級別、超時時間、是否只讀。

2.5 BeanFactoryTransactionAttributeSourceAdvisor

這個類的類圖:

BeanFactoryTransactionAttributeSourceAdvisor

它的實現:

/**
 * bean 工廠事務屬性源增強器
 *
 * Advisor driven by a {@link TransactionAttributeSource}, used to include
 * a transaction advice bean for methods that are transactional.
 *
 * @author Juergen Hoeller
 * @since 2.5.5
 * @see #setAdviceBeanName
 * @see TransactionInterceptor
 * @see TransactionAttributeSourceAdvisor
 */
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	/**
	 * 事務屬性源切點
	 */
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			// 獲取事務屬性源 AnnotationTransactionAttributeSource 類型
			return transactionAttributeSource;
		}
	};


	/**
	 * 通過注入
	 * Set the transaction attribute source which is used to find transaction
	 * attributes. This should usually be identical to the source reference
	 * set on the transaction interceptor itself.
	 * @see TransactionInterceptor#setTransactionAttributeSource
	 */
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	/**
	 * Set the {@link ClassFilter} to use for this pointcut.
	 * Default is {@link ClassFilter#TRUE}.
	 */
	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

它是一個 PointcutAdvisor 類型實現類,切點增強器,它也是實現 getPointcut() 方法,返回一個 TransactionAttributeSourcePointcut 類,這個類在上面的 canApply() 方法中用到了。

2.6 TransactionInterceptor

這個類的類圖:

TransactionInterceptor

再看下它的實現:

@SuppressWarnings("serial")
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

	/**
	 * Create a new TransactionInterceptor.
	 * <p>Transaction manager and transaction attributes still need to be set.
	 * @see #setTransactionManager
	 * @see #setTransactionAttributes(java.util.Properties)
	 * @see #setTransactionAttributeSource(TransactionAttributeSource)
	 */
	public TransactionInterceptor() {
	}

	/**
	 * Create a new TransactionInterceptor.
	 * @param ptm the default transaction manager to perform the actual transaction management
	 * @param tas the attribute source to be used to find transaction attributes
	 * @since 5.2.5
	 * @see #setTransactionManager
	 * @see #setTransactionAttributeSource
	 */
	public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) {
		setTransactionManager(ptm);
		setTransactionAttributeSource(tas);
	}

	/**
	 * Create a new TransactionInterceptor.
	 * @param ptm the default transaction manager to perform the actual transaction management
	 * @param tas the attribute source to be used to find transaction attributes
	 * @see #setTransactionManager
	 * @see #setTransactionAttributeSource
	 * @deprecated as of 5.2.5, in favor of
	 * {@link #TransactionInterceptor(TransactionManager, TransactionAttributeSource)}
	 */
	@Deprecated
	public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
		setTransactionManager(ptm);
		setTransactionAttributeSource(tas);
	}

	/**
	 * Create a new TransactionInterceptor.
	 * @param ptm the default transaction manager to perform the actual transaction management
	 * @param attributes the transaction attributes in properties format
	 * @see #setTransactionManager
	 * @see #setTransactionAttributes(java.util.Properties)
	 * @deprecated as of 5.2.5, in favor of {@link #setTransactionAttributes(Properties)}
	 */
	@Deprecated
	public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
		setTransactionManager(ptm);
		setTransactionAttributes(attributes);
	}

	/**
	 * 事務攔截器進行攔截調用
	 *
	 * @param invocation the method invocation joinpoint
	 * @return
	 * @throws Throwable
	 */
	@Override
	@Nullable
	public Object invoke(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, invocation::proceed);
	}


	//---------------------------------------------------------------------
	// Serialization support
	//---------------------------------------------------------------------

	private void writeObject(ObjectOutputStream oos) throws IOException {
		// Rely on default serialization, although this class itself doesn't carry state anyway...
		oos.defaultWriteObject();

		// Deserialize superclass fields.
		oos.writeObject(getTransactionManagerBeanName());
		oos.writeObject(getTransactionManager());
		oos.writeObject(getTransactionAttributeSource());
		oos.writeObject(getBeanFactory());
	}

	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
		// Rely on default serialization, although this class itself doesn't carry state anyway...
		ois.defaultReadObject();

		// Serialize all relevant superclass fields.
		// Superclass can't implement Serializable because it also serves as base class
		// for AspectJ aspects (which are not allowed to implement Serializable)!
		setTransactionManagerBeanName((String) ois.readObject());
		setTransactionManager((PlatformTransactionManager) ois.readObject());
		setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
		setBeanFactory((BeanFactory) ois.readObject());
	}

}

TransactionInterceptor 是一個實現了 MethodInterceptor 接口的 invoke() 方法,對方法執行進行攔截,間接調用了 org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 方法:

	/**
	 * 用於基於環繞通知子類的總代表,委派到該類的其他幾個模板方法。能夠處理 CallbackPreferringPlatformTransactionManager
	 * 和常規的 PlatformTransactionManager 實現類以及 ReactiveTransactionManager 實現類,對於無返回類型。
	 *
	 * General delegate for around-advice-based subclasses, delegating to several other template
	 * methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
	 * as well as regular {@link PlatformTransactionManager} implementations and
	 * {@link ReactiveTransactionManager} implementations for reactive return types.
	 * @param method the Method being invoked
	 * @param targetClass the target class that we're invoking the method on
	 * @param invocation the callback to use for proceeding with the target invocation
	 * @return the return value of the method, if any
	 * @throws Throwable propagated from the target invocation
	 */
	@Nullable
	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		// 如果事務屬性爲空,那麼這個方法就是非事務方法
		// If the transaction attribute is null, the method is non-transactional.
		// 獲取事務屬性源
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 獲取事務屬性
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 獲取項目中事務管理器,一般是 DataSourceTransactionManager 類
		final TransactionManager tm = determineTransactionManager(txAttr);

		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
					throw new TransactionUsageException(
							"Unsupported annotated transaction on suspending function detected: " + method +
							". Use TransactionalOperator.transactional extensions instead.");
				}
				ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
				if (adapter == null) {
					throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
							method.getReturnType());
				}
				return new ReactiveTransactionSupport(adapter);
			});
			return txSupport.invokeWithinTransaction(
					method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
		}

		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		// 獲取我們需要切入的方法(也就是我們標識了 @Transactional 註解的方法)
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// 事務信息
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			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;
			}
			finally {
				// 清理事務信息
				cleanupTransactionInfo(txInfo);
			}

			if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}

			// 提交事務
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			Object result;
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
					try {
						Object retVal = invocation.proceedWithInvocation();
						if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
							// Set rollback-only in case of Vavr failure matching our rollback rules...
							retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
						}
						return retVal;
					}
					catch (Throwable ex) {
						if (txAttr.rollbackOn(ex)) {
							// A RuntimeException: will lead to a rollback.
							if (ex instanceof RuntimeException) {
								throw (RuntimeException) ex;
							}
							else {
								throw new ThrowableHolderException(ex);
							}
						}
						else {
							// A normal return value: will lead to a commit.
							throwableHolder.throwable = ex;
							return null;
						}
					}
					finally {
						cleanupTransactionInfo(txInfo);
					}
				});
			}
			catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
			catch (TransactionSystemException ex2) {
				if (throwableHolder.throwable != null) {
					logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
					ex2.initApplicationException(throwableHolder.throwable);
				}
				throw ex2;
			}
			catch (Throwable ex2) {
				if (throwableHolder.throwable != null) {
					logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
				}
				throw ex2;
			}

			// Check result state: It might indicate a Throwable to rethrow.
			if (throwableHolder.throwable != null) {
				throw throwableHolder.throwable;
			}
			return result;
		}
	}

梳理下這個方法的核心流程:

  1. 獲取事務屬性源 TransactionAttributeSource;
  2. 獲取事務屬性 TransactionAttribute,這裏會返回 RuleBasedTransactionAttribute 類型;
  3. 獲取事務管理器 TransactionManager;
  4. 獲取方法描述器 joinpointIdentification;
  5. 執行 createTransactionIfNecessary() 方法,創建事務信息 TransactionInfo;
  6. 執行 invocation.proceedWithInvocation() 執行器方法,這將會執行調用鏈中下一個攔截器,如果沒有攔截,則執行目標方法;
  7. 遇到異常之後執行 completeTransactionAfterThrowing() 方法,進行回滾或提交操作,然後拋出異常;
  8. 執行 cleanupTransactionInfo() 方法,清除事務信息;
  9. 沒有異常的情況,執行 commitTransactionAfterReturning() 提交事務;
  10. 返回執行結果。

2.6.1 創建事務信息 createTransactionIfNecessary()

看下 org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary 這個創建事務信息方法:

	/**
	 * 根據給定的事務屬性來創建一個事務。
	 *
	 * Create a transaction if necessary based on the given TransactionAttribute.
	 * <p>Allows callers to perform custom TransactionAttribute lookups through
	 * the TransactionAttributeSource.
	 * @param txAttr the TransactionAttribute (may be {@code null})
	 * @param joinpointIdentification the fully qualified method name
	 * (used for monitoring and logging purposes)
	 * @return a TransactionInfo object, whether or not a transaction was created.
	 * The {@code hasTransaction()} method on TransactionInfo can be used to
	 * tell if there was a transaction created.
	 * @see #getTransactionAttributeSource()
	 */
	@SuppressWarnings("serial")
	protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		// 包裝事務屬性,名稱爲方法描述符
		// If no name specified, apply method identification as transaction name.
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		// 獲取一個事務狀態
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
				// 獲取事務,返回事務狀態
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		// 準備事務信息
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

它的邏輯:

  1. 通過事務管理器獲取事務狀態 getTransaction();
  2. 準備事務信息 prepareTransactionInfo(),創建事務信息 TransactionInfo 類;

2.6.1.1 獲取事務狀態 getTransaction()

看下如何獲取事務狀態信息:org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

	/**
	 * 實現處理傳播行爲的方法,委派到 doGetTransaction、isExistingTransaction、doBegin 方法
	 *
	 * This implementation handles propagation behavior. Delegates to
	 * {@code doGetTransaction}, {@code isExistingTransaction}
	 * and {@code doBegin}.
	 * @see #doGetTransaction
	 * @see #isExistingTransaction
	 * @see #doBegin
	 */
	@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// 獲取事務定義
		// Use defaults if no transaction definition given.
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

		// 獲取事務對象
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

		// 判斷是否存在事務
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			// 處理已存在的事務
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// 判斷事務超時
		// Check definition settings for new transaction.
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}

		// 判斷事務傳播行爲 MANDATORY 必須的
		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			// 掛起事務,但是當前沒有事務
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				// 開始一個新的事務
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				// 重新使用資源
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// 創建一個空的事務,但是它會潛在的同步
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

它的邏輯:

  1. 執行 doGetTransaction() 方法,獲取事務對象,返回一個 DataSourceTransactionObject 類型對象;
  2. 判斷是否存在事務 isExistingTransaction();
  3. 如果存在事務,執行 handleExistingTransaction() 方法,處理已存在的事務,結束;
  4. 判斷事務是否超時,判斷正確的傳播行爲;
  5. 判斷傳播行爲如果是支持當前事務的(REQUIRED、REQUIRED_NEW、NESTED),先執行 suspend() 方法,掛起當前事務,然後執行 startTransaction() 開啓一個新事物,結束;
  6. 否則執行 prepareTransactionStatus() 方法,創建一個空的事務,結束。

2.6.1.2 獲取 DataSourceTransactionObject 事務對象 doGetTransaction()

看下它的實現 org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction:

	/**
	 * 獲取事務對象
	 *
	 * @return
	 */
	@Override
	protected Object doGetTransaction() {
		// 創建一個數據源事務對象
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		// 設置允許嵌套事務(保存點)
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		// 獲取連接持有器
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		// 爲數據源事務對象設置連接持有器(首次獲取爲空)
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

可以看到事務對象是一個 DataSourceTransactionObject 類型的對象,它的類圖結構:

DataSourceTransactionObject

它擁有的屬性有:連接持有器、是否允許保存點、是否只讀、前一個事務隔離級別、是否新的連接持有器、是否僅支持回滾、是否必須還原自動提交屬性等等。

上面的 doGetTransaction() 方法邏輯:

  1. 創建一個 DataSourceTransactionObject 類型對象;
  2. 設置是否允許保存點(即是否允許嵌套事務);
  3. 獲取連接持有器(這裏是從線程本地化中獲取的,首次獲取爲 null);
  4. 爲事務對象設置連接持有器。

2.6.1.3 判斷是否存在事務 isExistingTransaction()

我們先看下它是如何判斷事務是否存在的:org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction

	/**
	 * 判斷是否存在事務
	 *
	 * @param transaction the transaction object returned by doGetTransaction
	 * @return
	 */
	@Override
	protected boolean isExistingTransaction(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		// 事務有連接持有器 && 連接持有器中的事務是活躍的
		return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
	}
  1. 事務對象是否有連接持有器;
  2. 連接持有器中的事務是否是活躍的。

2.6.1.4 處理已存在的事務 handleExistingTransaction()

接着看處理已經存在的事務 org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction 方法:

	/**
	 * 爲一個已經存在的事務,創建一個事務狀態
	 *
	 * Create a TransactionStatus for an existing transaction.
	 */
	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

		// 判斷傳播行爲:never 拋出異常
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}

		// 傳播行爲是 NOT_SUPPORTED 不執行事務
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction");
			}
			// 掛起當前事務
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			// 準備事務狀態
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		// 傳播行爲:REQUIRES_NEW 開啓一個新的事務
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}
			// 掛起當前事務
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
				// 開啓一個新的事務
				return startTransaction(definition, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}

		// 傳播行爲:NESTED 嵌套事務
		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 (debugEnabled) {
				logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
			}
			// 是否爲嵌套事務保存點
			if (useSavepointForNestedTransaction()) {
				// Create savepoint within existing Spring-managed transaction,
				// through the SavepointManager API implemented by TransactionStatus.
				// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
				// 創建一個新的事務狀態
				DefaultTransactionStatus status =
						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
				// 創建和持有保存點
				status.createAndHoldSavepoint();
				return status;
			}
			else {
				// Nested transaction through nested begin and commit/rollback calls.
				// Usually only for JTA: Spring synchronization might get activated here
				// in case of a pre-existing JTA transaction.
				// 開啓事務
				return startTransaction(definition, transaction, debugEnabled, null);
			}
		}

		// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
		if (debugEnabled) {
			logger.debug("Participating in existing transaction");
		}

		// 驗證現有的事務
		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");
				}
			}
		}
		// 傳播行爲:不是 NEVER,準備事務狀態
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

邏輯:

  1. 判斷傳播行爲,不同的傳播行爲執行不同的邏輯;
  2. 傳播行爲是 NOT_SUPPORTED 不執行事務;
    1. 先執行 suspend() 掛起當前事務;
    2. 執行 prepareTransactionStatus() 準備事務。
  3. 傳播行爲是 REQUIRES_NEW 開啓新事物;
    1. 先執行 suspend() 掛起當前事務;
    2. 執行 startTransaction() 開啓一個新事物。
  4. 傳播行爲是 NESTED 嵌套事務;
    1. 判斷是否爲嵌套事務使用保存點;
    2. 如果不是,則執行 startTransaction() 方法,開啓一個新事物;
    3. 如果是,則先執行 prepareTransactionStatus() 創建一個新的事務狀態 DefaultTransactionStatus,然後執行事務狀態的 createAndHoldSavepoint() 創建保存點,返回。
  5. 驗證現有的事務;
  6. 其他的傳播行爲,執行 prepareTransactionStatus() 方法,準備事務狀態。

2.6.1.5 掛起事務 suspend()

掛起事務是 org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend 方法中實現的:

	/**
	 * 掛起給定的事務。首先掛起事務同步,然後委派 doSuspend 模板方法。
	 *
	 * Suspend the given transaction. Suspends transaction synchronization first,
	 * then delegates to the {@code doSuspend} template method.
	 * @param transaction the current transaction object
	 * (or {@code null} to just suspend active synchronizations, if any)
	 * @return an object that holds suspended resources
	 * (or {@code null} if neither transaction nor synchronization active)
	 * @see #doSuspend
	 * @see #resume
	 */
	@Nullable
	protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
		// 判斷是否同步是活躍的
		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			// 執行掛起同步
			List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
			try {
				Object suspendedResources = null;
				if (transaction != null) {
					// 對給定的事務進行掛起,返回一個當前連接資源
					suspendedResources = doSuspend(transaction);
				}
				// 清除當前事務信息
				// 當前事務名稱
				String name = TransactionSynchronizationManager.getCurrentTransactionName();
				TransactionSynchronizationManager.setCurrentTransactionName(null);
				// 是否只讀
				boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
				TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
				// 隔離級別
				Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
				TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
				// 是哦福活躍
				boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
				TransactionSynchronizationManager.setActualTransactionActive(false);
				// 創建新一個掛起資源持有器,把當前事務信息都保存起來
				return new SuspendedResourcesHolder(
						suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
			}
			catch (RuntimeException | Error ex) {
				// doSuspend failed - original transaction is still active...
				doResumeSynchronization(suspendedSynchronizations);
				throw ex;
			}
		}
		else if (transaction != null) {
			// Transaction active but no synchronization active.
			Object suspendedResources = doSuspend(transaction);
			return new SuspendedResourcesHolder(suspendedResources);
		}
		else {
			// Neither transaction nor synchronization active.
			return null;
		}
	}

	/**
	 * 掛起所有的當前同步,並且取消激活當前線程的事務同步
	 * Suspend all current synchronizations and deactivate transaction
	 * synchronization for the current thread.
	 * @return the List of suspended TransactionSynchronization objects
	 */
	private List<TransactionSynchronization> doSuspendSynchronization() {
		// 獲取當前線程中全部的事務同步
		List<TransactionSynchronization> suspendedSynchronizations =
				TransactionSynchronizationManager.getSynchronizations();
		// 遍歷同步,使其依次掛起
		for (TransactionSynchronization synchronization : suspendedSynchronizations) {
			// 就是釋放數據庫連接資源
			synchronization.suspend();
		}
		// 清理同步
		TransactionSynchronizationManager.clearSynchronization();
		// 返回同步
		return suspendedSynchronizations;
	}

======================================= org.springframework.jdbc.datasource.DataSourceTransactionManager#doSuspend =======================================

	/**
	 * 執行掛起事務
	 *
	 * @param transaction the transaction object returned by {@code doGetTransaction}
	 * @return
	 */
	@Override
	protected Object doSuspend(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		txObject.setConnectionHolder(null);
		// 釋放資源
		return TransactionSynchronizationManager.unbindResource(obtainDataSource());
	}


它的邏輯是:

  1. 執行掛起同步 doSuspendSynchronization() 方法,這裏邊主要是從線程本地化中獲取所有的事務同步 TransactionSynchronization,然後執行掛起(就是釋放數據庫連接資源);
  2. 然後執行 doSuspend() 方法,掛起給定的事務,返回一個當前連接資源;
  3. 清除線程本地化中當前的事務信息,有線程名稱、線程只讀屬性、線程隔離級別、事務是否活躍標識;
  4. 創建一個掛起的資源持有器 SuspendedResourcesHolder,返回。
  5. 遇到異常執行 doResumeSynchronization() 方法,重新使用同步。

2.6.1.6 準備事務狀態 prepareTransactionStatus()

接着看準備事務狀態方法 org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareTransactionStatus :

	/**
	 * 創建一個新的事務狀態,同時初始化事務同步。
	 *
	 * Create a new TransactionStatus for the given arguments,
	 * also initializing transaction synchronization as appropriate.
	 * @see #newTransactionStatus
	 * @see #prepareTransactionStatus
	 */
	protected final DefaultTransactionStatus prepareTransactionStatus(
			TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
			boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
		// 創建一個新的事務狀態
		DefaultTransactionStatus status = newTransactionStatus(
				definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
		// 預同步事務
		prepareSynchronization(status, definition);
		return status;
	}

	/**
	 * Create a TransactionStatus instance for the given arguments.
	 */
	protected DefaultTransactionStatus newTransactionStatus(
			TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
			boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {

		boolean actualNewSynchronization = newSynchronization &&
				!TransactionSynchronizationManager.isSynchronizationActive();
		// 創建一個默認的事務狀態
		return new DefaultTransactionStatus(
				transaction, newTransaction, actualNewSynchronization,
				definition.isReadOnly(), debug, suspendedResources);
	}

	/**
	 * Initialize transaction synchronization as appropriate.
	 */
	protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
		// 判斷是否爲新的同步
		if (status.isNewSynchronization()) {
			// 設置實際事務活躍
			TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
			// 設置當前事務隔離級別
			TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
					definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
							definition.getIsolationLevel() : null);
			// 設置當前事務是否爲只讀
			TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
			// 設置當前事務的名稱
			TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
			// 初始化同步
			TransactionSynchronizationManager.initSynchronization();
		}
	}

邏輯:

  1. 執行 newTransactionStatus() 方法,創建一個事務狀態 DefaultTransactionStatus 對象;
  2. 執行 prepareSynchronization() 方法,準備同步。
    1. 判斷事務狀態如果是新的同步,則執行以下邏輯;
    2. 設置線程本地化的實際事務活躍;
    3. 設置線程本地化的當前事務隔離級別;
    4. 設置線程本地化的當前事務是否爲只讀標識;
    5. 設置當前事務的名稱;
    6. 初始化線程本地化同步集合。

2.6.1.7 事務狀態 DefaultTransactionStatus

我們看下 DefaultTransactionStatus 對象的類圖:

DefaultTransactionStatus

這個類有持有了一些事務的屬性,表示當前事務的一個狀態。

2.6.1.8 開啓一個新事物 startTransaction()

開始看開啓新事物方法 org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction :

	/**
	 * 開啓一個新的事務
	 *
	 * Start a new transaction.
	 */
	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;
	}

================================ org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin ================================
	/**
	 * 開啓一個新的事務
	 *
	 * @param transaction the transaction object returned by {@code doGetTransaction}
	 * @param definition  a TransactionDefinition instance, describing propagation
	 *                    behavior, isolation level, read-only flag, timeout, and transaction name
	 */
	@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			// 判斷是否有連接持有器
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				// 獲取一個新的連接
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				// 創建一個新的連接持有器,設置到事務對象中
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			// 設置連接持有器的事務同步屬性
			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			// 獲取連接對象
			con = txObject.getConnectionHolder().getConnection();

			// 預設值連接屬性,返回隔離級別
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			// 爲事務對象設置隔離級別
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			// 設置只讀屬性
			txObject.setReadOnly(definition.isReadOnly());

			// 獲取自定提交的屬性,設置爲 false
			// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
			// so we don't want to do it unnecessarily (for example if we've explicitly
			// configured the connection pool to set it already).
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			// 預處理事務連接
			prepareTransactionalConnection(con, definition);
			// 設置事務對象的連接持有器的活躍屬性
			txObject.getConnectionHolder().setTransactionActive(true);

			// 超時時間
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// 綁定一個資源
			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
			// 遇到異常,釋放資源
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				// 清空連接持有器
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}


它的邏輯:

  1. 執行 newTransactionStatus() 方法,創建一個事務狀態 DefaultTransactionStatus 對象;
  2. 執行 doBegin() 方法,開啓事務;
    1. 判斷事務對象 DataSourceTransactionObject 是否有連接持有器;
    2. 如果沒有,創建一個新的連接 Connection、連接持有器 ConnectionHolder,並設置到事務對象中;
    3. 設置連接持有器的同步標識;
    4. 獲取連接,爲事務準備連接,
    5. 設置事務對象只讀標識屬性、隔離級別屬性;
    6. 關閉連接的自動提交;
    7. 準備事務連接;
    8. 設置連接持有器的事務激活標識爲 true;
    9. 設置事務對象的超時時間;
    10. 持有器是新的話,就綁定一個連接資源,到線程本地化中。
    11. 遇到異常,持有器是新的話,就釋放資源,清空事務對象的連接持有器。
  3. 執行 prepareSynchronization() 方法,準備同步。

2.6.1.9 準備事務信息 prepareTransactionInfo()

獲取了一個事務狀態之後,接着到了準備事務信息方法了,org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo:

	/**
	 * 準備一個事務信息。
	 *
	 * Prepare a TransactionInfo for the given attribute and status object.
	 * @param txAttr the TransactionAttribute (may be {@code null})
	 * @param joinpointIdentification the fully qualified method name
	 * (used for monitoring and logging purposes)
	 * @param status the TransactionStatus for the current transaction
	 * @return the prepared TransactionInfo object
	 */
	protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, String joinpointIdentification,
			@Nullable TransactionStatus status) {

		// 創建一個事務信息
		TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
		if (txAttr != null) {
			// We need a transaction for this method...
			if (logger.isTraceEnabled()) {
				logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			// 設置事務狀態
			// The transaction manager will flag an error if an incompatible tx already exists.
			txInfo.newTransactionStatus(status);
		}
		else {
			// The TransactionInfo.hasTransaction() method will return false. We created it only
			// to preserve the integrity of the ThreadLocal stack maintained in this class.
			if (logger.isTraceEnabled()) {
				logger.trace("No need to create transaction for [" + joinpointIdentification +
						"]: This method is not transactional.");
			}
		}

		// We always bind the TransactionInfo to the thread, even if we didn't create
		// a new transaction here. This guarantees that the TransactionInfo stack
		// will be managed correctly even if no transaction was created by this aspect.
		// 綁定線程
		txInfo.bindToThread();
		return txInfo;
	}

邏輯:

  1. 創建一個事務信息 TransactionInfo 對象;
  2. 設置事務信息的事務狀態屬性;
  3. 把事務信息綁定到綁定線程,保存舊的事務信息,把當前事務信息綁定到線程本地化中;
  4. 返回事務信息。

我們看下這個 TransactionInfo 類信息:

TransactionInfo

它持有一個事務狀態、事務管理器、事務屬性、方法切點。

2.6.2 處理異常 completeTransactionAfterThrowing()

在執行器執行過程中遇到異常時,會執行 org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing 方法:

	/**
	 * Handle a throwable, completing the transaction.
	 * We may commit or roll back, depending on the configuration.
	 * @param txInfo information about the current transaction
	 * @param ex throwable encountered
	 */
	protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
						"] after exception: " + ex);
			}
			// 判斷是否對該異常進行回滾
			if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
				try {
					// 進行回滾
					txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					throw ex2;
				}
			}
			else {
				// 我們不會回滾這個異常。
				// 如果 TransactionStatus.isRollbackOnly() 是 true,則任然回滾
				// We don't roll back on this exception.
				// Will still roll back if TransactionStatus.isRollbackOnly() is true.
				try {
					txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					throw ex2;
				}
			}
		}
	}

邏輯爲:

  1. 判斷是否對該異常進行回滾;
  2. 如果需要,則進行回滾;
  3. 如果不需要則執行提交事務。

2.6.3 清理事務信息 cleanupTransactionInfo()

當目標方法都處理完畢之後,不論有沒有異常拋出,都進行清除事務信息 org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo:

	/**
	 * Reset the TransactionInfo ThreadLocal.
	 * <p>Call this in all cases: exception or normal return!
	 * @param txInfo information about the current transaction (may be {@code null})
	 */
	protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
		if (txInfo != null) {
			// 恢復線程本地化狀態
			txInfo.restoreThreadLocalStatus();
		}
	}

		private void restoreThreadLocalStatus() {
			// Use stack to restore old transaction TransactionInfo.
			// Will be null if none was set.
			// 還原上一個事務信息
			transactionInfoHolder.set(this.oldTransactionInfo);
		}

主要是還原上一個事務信息到線程本地中。

2.6.4 提交事務 commitTransactionAfterReturning()

最後,當方法執行完畢,沒有異常的情況下,會執行提交事務操作 org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning:

	/**
	 * Execute after successful completion of call, but not after an exception was handled.
	 * Do nothing if we didn't create a transaction.
	 * @param txInfo information about the current transaction
	 */
	protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			// 提交事務
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}


======================== org.springframework.transaction.support.AbstractPlatformTransactionManager#commit ====================
	/**
	 * This implementation of commit handles participating in existing
	 * transactions and programmatic rollback requests.
	 * Delegates to {@code isRollbackOnly}, {@code doCommit}
	 * and {@code rollback}.
	 * @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
	 * @see #doCommit
	 * @see #rollback
	 */
	@Override
	public final void commit(TransactionStatus status) throws TransactionException {
		if (status.isCompleted()) {
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}

		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		// 事務狀態是僅回滾的,執行回滾
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}

		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			processRollback(defStatus, true);
			return;
		}

		// 執行提交
		processCommit(defStatus);
	}

	/**
	 * 處理實際的回滾。已經檢查了完成標記。
	 *
	 * Process an actual rollback.
	 * The completed flag has already been checked.
	 * @param status object representing the transaction
	 * @throws TransactionException in case of rollback failure
	 */
	private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
			boolean unexpectedRollback = unexpected;

			try {
				// 觸發前置完成事件
				triggerBeforeCompletion(status);

				// 判斷保存點
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}
					// 回滾到保存點
					status.rollbackToHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction rollback");
					}
					// 新的事務,進行回滾
					doRollback(status);
				}
				else {
					// Participating in larger transaction
					// 判斷是否有事務
					if (status.hasTransaction()) {
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
							// 設置僅回滾屬性
							doSetRollbackOnly(status);
						}
						else {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
							}
						}
					}
					else {
						logger.debug("Should roll back transaction but cannot - no transaction available");
					}
					// Unexpected rollback only matters here if we're asked to fail early
					if (!isFailEarlyOnGlobalRollbackOnly()) {
						unexpectedRollback = false;
					}
				}
			}
			catch (RuntimeException | Error ex) {
				// 觸發完成之後事件
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw ex;
			}
			// 觸發完成之後事件
			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

			// Raise UnexpectedRollbackException if we had a global rollback-only marker
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
		}
		finally {
			// 完成之後的清理事件
			cleanupAfterCompletion(status);
		}
	}

	/**
	 * Process an actual commit.
	 * Rollback-only flags have already been checked and applied.
	 * @param status object representing the transaction
	 * @throws TransactionException in case of commit failure
	 */
	private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;

				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					// 釋放保存點
					status.releaseHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					// 執行提交
					doCommit(status);
				}
				else if (isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = status.isGlobalRollbackOnly();
				}

				// Throw UnexpectedRollbackException if we have a global rollback-only
				// marker but still didn't get a corresponding exception from commit.
				if (unexpectedRollback) {
					throw new UnexpectedRollbackException(
							"Transaction silently rolled back because it has been marked as rollback-only");
				}
			}
			catch (UnexpectedRollbackException ex) {
				// can only be caused by doCommit
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
				throw ex;
			}
			catch (TransactionException ex) {
				// can only be caused by doCommit
				if (isRollbackOnCommitFailure()) {
					doRollbackOnCommitException(status, ex);
				}
				else {
					triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				}
				throw ex;
			}
			catch (RuntimeException | Error ex) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, ex);
				throw ex;
			}

			// Trigger afterCommit callbacks, with an exception thrown there
			// propagated to callers but the transaction still considered as committed.
			try {
				triggerAfterCommit(status);
			}
			finally {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
			}

		}
		finally {
			cleanupAfterCompletion(status);
		}
	}

這裏的邏輯稍微複雜點:

  1. 判斷事務狀態是否是僅回滾的,如果是那就執行 processRollback() 方法,執行回滾;
    1. 執行 triggerBeforeCompletion() 方法,觸發前置完成事件,底層調用事務同步 TransactionSynchronization 的 beforeCompletion() 方法;
    2. 判斷一下條件,執行各自的邏輯
      1. 如果有保存點,那就執行事務狀態的 rollbackToHeldSavepoint() 方法,回滾到保存點;
      2. 如果是新事物,執行 doRollback() 方法,進行回滾;
      3. 都不是,則執行 doSetRollbackOnly() 方法,給事務對象設置回滾標識,讓上層事務進行回滾。
    3. 執行 triggerAfterCompletion() 方法,執行完成操作,底層調用事務同步 TransactionSynchronization 的 afterCompletion() 方法;
    4. 最後執行 cleanupAfterCompletion() 方法,進行清除操作。
      1. 新的同步則執行清理線程本地化操作;
      2. 新的事務,則執行釋放連接操作;
      3. 如果有掛起的資源,恢復掛起的資源。
  2. 不是的話,就執行 processCommit() 方法,進行提交。
    1. 執行 triggerBeforeCommit() 方法,執行提交前的操作,底層調用事務同步 TransactionSynchronization 的 beforeCommit() 方法;
    2. 執行 triggerBeforeCompletion() 方法,執行完成前的操作,底層調用事務同步 TransactionSynchronization 的 beforeCompletion() 方法;
    3. 判斷一下條件,執行各自的邏輯;
      1. 如果有保存點,則執行事務狀態的 releaseHeldSavepoint() 方法,釋放保存點;
      2. 如果是新的事務,則執行 doCommit() 方法,進行提交;
      3. 全局回滾時提前失敗檢查。
    4. 執行 triggerAfterCompletion() 方法,執行完成之後的操作,底層調用事務同步 TransactionSynchronization 的 afterCompletion() 方法;
    5. 遇到異常時,執行 doRollbackOnCommitException() 方法,進行回滾;
    6. 沒有遇到異常,執行 triggerAfterCommit() 方法,執行完成之後的操作;
    7. 最後執行 cleanupAfterCompletion() 方法,進行清理操作。
      1. 新的同步則執行清理線程本地化操作;
      2. 新的事務,則執行釋放連接操作;
      3. 如果有掛起的資源,恢復掛起的資源。

總結

上面就是 spring tx 模板的核心流程了。回顧下:

  1. 通過 @EnableTransactionManagement 註解,導入了 TransactionManagementConfigurationSelector 類;
  2. TransactionManagementConfigurationSelector 類,它導入了AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 類;
  3. AutoProxyRegistrar 類負責註冊一個 InfrastructureAdvisorAutoProxyCreator 類,它是一個創建代理對象的後置處理器;
  4. ProxyTransactionManagementConfiguration 類是創建了負責處理事務的增強器 BeanFactoryTransactionAttributeSourceAdvisor、還有處理事務屬性的事務屬性源 AnnotationTransactionAttributeSource、以及對目標方法進行事務處理攔截的事務攔截器 TransactionInterceptor,這三個 bean;
  5. 其中在調用目標方法時,通過事務攔截器 TransactionInterceptor 對目標方法進行攔截;
  6. 攔截有創建以及初始化事務相關信息(事務狀態、事務對象、事務同步等信息)、執行目標方法、提交或者回滾事務、清理事務等流程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章