Spring事務源碼閱讀(註解式和xml配置式)

本文參考:《Spring源碼深度解析》及源碼走讀.培養源碼閱讀思想

文章目錄


先放圖,du害一下大家,在這裏插入圖片描述
在這裏插入圖片描述

1.必須懂的幾個類

試想一下,如果Connection支持事務提交回滾(底層支持),那麼你如何來設計你的事務處理框架?
我相信很多人的想法都是

  • 先讀取 @Transation註解的屬性.生成一個對象(存放事務相關)
  • 根據得到的該對象進行事務的commit,失敗回滾,最終事務清除.

Spring框架對事務的支持大概也是這樣的步驟,Spring支持嵌入事務,即方法中嵌套方法,如果都支持事務,則在裏面的事務結束或者失敗之後,外面的事務繼續執行.
我們剛纔提到 @Transation註解的屬性提取,那麼必定需要這樣一個類去做提取的操作,提取的對象存儲也需要一個相應類,用什麼方式執行事務,這些都是我們後面需要討論的內容,但是,在此之前,我們先看幾個類,我們已經知道了實現事務的大概步驟,那麼我們需要來看一下,Spring怎麼去實現這些步驟的.

2.1 提取器驅動(裝載)的advisor:BeanFactoryTransactionAttributeSourceAdvisor

我們知道Spring框架大量的使用了接口,可以想象,對於 @Transation註解的提取,Spring必定也是通過接口的實現類來定義提取方法(下一個會講到),所以我們可以想象,我們需要一個類來承接這些接口和其他的屬性.我們這裏要講的就是這個類。
我們看一下類上的註解:

  • Advisor driven by a TransactionAttributeSource, used to include a transaction advice bean for methods that are transactional.

包含一個 TransactionAttributeSource,用於事務通知。我們暫且不管 TransactionAttributeSource類的作用,目前我們可以知道的就是BeanFactoryTransactionAttributeSourceAdvisor他會裝載和提供一個 TransactionAttributeSource類。
我們看他是怎麼實現 TransactionAttributeSource的。

@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
	
	//這個就是我們念念不忘的TransactionAttributeSource
	private TransactionAttributeSource transactionAttributeSource;

    //因爲BeanFactoryTransactionAttributeSourceAdvisor 繼承了PointCut接口,所以需要實現getPointCut方法
    //而獲取到的PointCut類會返回我們需要的TransactionAttributeSource。
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};
	
	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}
}

很容易我們看到了TransactionAttributeSource 這個類,並且因爲BeanFactoryTransactionAttributeSourceAdvisor繼承了Pointcut接口,需要實現getPointcut方法,相當於是
通過得到PointCut實現類,再獲取TransactionAttributeSource

2.2 @Transation註解元數據提取器:TransactionAttributeSource

@Transation的提取需要一定的規則,而不同的方式可能對應不同的規則,所以Spring利用接口的方式,制定提取的抽象。通過繼承實現不同的提取規則。
首先你要知道 TransactionAttributeSource是一個接口,我們看一下類的描述

  • Strategy interface used by TransactionInterceptor for metadata retrieval.
    Implementations know how to source transaction attributes, whether from configuration, metadata attributes at source level (such as Java 5 annotations), or anywhere else.

提供給TransactionInterceptor攔截器用於事務元數據提取的接口.
但是接口需要實現類,因爲是註解解析,這邊的具體實現類是 AnnotationTransactionAttributeSource
作爲一個註解提取器, AnnotationTransactionAttributeSource如何實現提取呢?

3.1 真實註解處理器:TransactionAnnotationParser

這邊就給你答案,那就是TransactionAnnotationParser,看到該類的構造方法.必定會注入SpringTransactionAnnotationParser,這個類,這也是我們後面處理註解需要注意的。

	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		if (jta12Present) {
			this.annotationParsers.add(new JtaTransactionAnnotationParser());
		}
		if (ejb3Present) {
			this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
		}
	}

2.3 事務執行器\攔截器:TransactionInterceptor

首先知道一點就是 ****實現了 MethodInterceptor接口,需要實現這個類的 invoke方法,事務處理的具體邏輯就在這裏,而 MethodInterceptor又會在代理創建的時候被調用,所以我們基本知道該攔截器實現事務管理是通過invoke方法在代理的時候實現。
我們在後面的描述中會講到具體實現,彆着急
關注一下類上的註釋:

  • AOP Alliance MethodInterceptor for declarative transaction management using the common Spring transaction infrastructure (PlatformTransactionManager)
  • TransactionInterceptors are thread-safe.

事務管理線程安全

2. 事務管理入口

2.1 註解式

還記得開啓事務的註解式什麼嗎?我錯,我知道你不記得了。
開啓事務的註解是 EnableTransactionManagement,我們可以查看一下這個註解的使用,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
	boolean proxyTargetClass() default false;
	
	//實現事務的方式(proxy或者aspectj)
	AdviceMode mode() default AdviceMode.PROXY;
	
	int order() default Ordered.LOWEST_PRECEDENCE;
}

很好,我們看到這個註解有一個mode,能夠配置事務管理實現的方式,默認是PROXY.
在註解上面有一個 @Import註解,如果你告訴我不懂,我就是一巴掌過去. @Import註解引入一個Selector類,我們要看一下他是做什麼幺蛾子的。

3.1 事務管理選擇器:TransactionManagementConfigurationSelector

這個註解繼承了AdviceModeImportSelector,實現selectImport方法,朔本回源,在Mvc啓動的時候會調用Selector,也就是這樣啓動的.這邊我們不細究,知道一個大概:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}
}

這裏看到了AdviceMode 的選擇,我們只分析PROXY的方式,不要問爲什麼,問就是我菜.
PROXY的方式會返回兩個類:AutoProxyRegistrar
ProxyTransactionManagementConfiguration

幺蛾子就出在這裏面.

4.1 註冊代理構造器:AutoProxyRegistrar

這個類只有一個方法,這個方法會去註冊一些BeanDefinition.

@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
		for (String annoType : annoTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
			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) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
	}

雖然這個類嘰裏呱啦的說了一堆,但是重要的是這一行代碼,這個方法會爲我們註冊一個很重要的類:InfrastructureAdvisorAutoProxyCreator,自動代理構造器,我們對於advisor的查找和代理的實現都在這個類中實現,後面我們會說道。

	AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

	public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
		return registerAutoProxyCreatorIfNecessary(registry, null);
	}

	public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
		return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
	}

4.2 事務註解驅動配置:ProxyTransactionManagementConfiguration

這個類,會爲我們註冊幾個Bean,就是我們一開頭說的,事務註解元數據提取器事務處理攔截器提取器承載類

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	//事務註解提取器的承載類
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		//注入事務註解提取器
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		//注入攔截器
		advisor.setAdvice(transactionInterceptor());
		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() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		//注入事務註解提取器
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			//事務管理器:PlatformTransactionManager
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

2.2 XML式

3.1 事務命名空間處理器:TxNamespaceHandler

這個類實現了NameSpaceHandler,Spring框架會實現NamespaceHandler接口實現類的調用,這個我們暫時不管他。
可以想象到,和註解處理的方式應該類似,這邊也應該注入,我們剛纔講的三個類.所以我們來看一下代碼實現

	@Override
	public void init() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}

這邊註冊了三個BeanDefinitionParser的類,用屁股想象都知道,他大概想要去做什麼事情,但是我們還是一個一個來看一下.

4.1 TxAdviceBeanDefinitionParser:註冊事務註解提取器(或直接讀取事務配置)

看到這邊會去提取xml的元素,然後判斷是否手動在XML中寫入了事務相關屬性,parseAttributeSource這個方法會去解析相關的屬性(只讀、超時時間…)
如果不是xml方式去注入的話,就需要去註冊一個AnnotationTransactionAttributeSource,讓這個類去提取**@Transational**上的屬性,然後生成對應類.

	@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
		builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));

		List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
		if (txAttributes.size() > 1) {
			parserContext.getReaderContext().error(
					"Element <attributes> is allowed at most once inside element <advice>", element);
		}
		else if (txAttributes.size() == 1) {
			// Using attributes source.
			Element attributeSourceElement = txAttributes.get(0);
			RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
			builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
		}
		else {
			// Assume annotations source.
			builder.addPropertyValue("transactionAttributeSource",
					new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
		}
	}

4.2 註冊事務基礎Bean配置

等下我們看代碼的時候你會發現,他實現了和事務註解驅動配置:ProxyTransactionManagementConfiguration類似的功能:

	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		registerTransactionalEventListenerFactory(parserContext);
		String mode = element.getAttribute("mode");
		if ("aspectj".equals(mode)) {
			// mode="aspectj"
			registerTransactionAspect(element, parserContext);
		}
		else {
			// mode="proxy"
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}

這邊我們依然只看PROXY的方式,我們可以看到下面的代碼基本可以分成四步:

  • AopNamespaceUtils.registerAutoProxyCreatorIfNecessary:註冊InfrastructureAdvisorAutoProxyCreator以及xml配置的解析,不具體看了
  • 注入AnnotationTransactionAttributeSource
  • 注入TransactionInterceptor
  • 注入BeanFactoryTransactionAttributeSourceAdvisor
  • 註冊上述的組件到context
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
			//註冊InfrastructureAdvisorAutoProxyCreator類和解析XML屬性
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

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

				//注入AnnotationTransactionAttributeSource
				RootBeanDefinition sourceDef = new RootBeanDefinition(
						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

				//注入TransactionInterceptor
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				registerTransactionManager(element, interceptorDef);
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

				//注入BeanFactoryTransactionAttributeSourceAdvisor
				RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
				advisorDef.setSource(eleSource);
				advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
				if (element.hasAttribute("order")) {
					advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
				}
				parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
				
				//註冊到context
				CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
				compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
				compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
				compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
				parserContext.registerComponent(compositeDef);
			}
		}
	}

4.3 註冊事務管理器

這個類應該是解析xml上面的註解來註冊事務管理器的,我們看一下這邊的註釋

  • Parser for the tx:jta-transaction-manager/ XML configuration element, autodetecting WebLogic and WebSphere servers and exposing the corresponding JtaTransactionManager subclass.

代碼裏面會根據不同的方式去註冊事務管理器.

	static String resolveJtaTransactionManagerClassName() {
		if (weblogicPresent) {
			return WEBLOGIC_JTA_TRANSACTION_MANAGER_CLASS_NAME;
		}
		else if (webspherePresent) {
			return WEBSPHERE_TRANSACTION_MANAGER_CLASS_NAME;
		}
		else {
			return JTA_TRANSACTION_MANAGER_CLASS_NAME;
		}
	}

3. 構造器:事務攔截器基本配置查找與生成代理

廢話不多說,我們來看一下InfrastructureAdvisorAutoProxyCreator這個類,這個類隔代實現了BeanPostProcessor接口,對於BeanPostProcessor,我們看一下類的註釋

  • Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.

大概就是爲Bean工廠創建的Bean實例提供一個鉤子,在Bean調用之前做一些修飾操作.
實現postProcessAfterInitialization才能實現上面所說的操作,我們看一下這個方法:
注意類上的註釋:通過配置監聽器實現代理,這邊設置緩存用過特定key查找,沒有找到會進入wrapIfNecessary方法,根據註釋,我們可以知道,這個方法大概就是要去生成一個代理了。

	/**
	 * Create a proxy with the configured interceptors if the bean is
	 * identified as one to proxy by the subclass.
	 * @see #getAdvicesAndAdvisorsForBean
	 */
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (!this.earlyProxyReferences.contains(cacheKey)) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

通過一些列的查找,如果找到對應的代理類就直接返回,否則

  • 先去查找攔截器
  • 在通過攔截器實現代理
	/**
	 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
	 * @param bean the raw bean instance
	 * @param beanName the name of the bean
	 * @param cacheKey the cache key for metadata access
	 * @return a proxy wrapping the bean, or the raw bean instance as-is
	 */
	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// 查找攔截器
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//生成代理
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

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

我們下面通過這兩部分來分析一下

2.1 攔截器查找

這裏進入攔截器的查找,如果查找到的攔截器爲空, 返回空數組,否則返回攔截器數組

	@Override
	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

查找過程又分成兩步

  • 查找所有攔截器
  • 根據找到的所有攔截器,查找合適的攔截器
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

3.1 查找所有攔截器

這邊的這個方法處理是這樣的

  • 從BeanFactory(或者緩存數組)中拿到advisor的字符串名稱
  • 進行一些判斷,然後從BeanFactory裏面獲取Advisor實例
  • 組裝List返回

雖然我不知道BeanFactory怎麼去拿到這些advisor,能力有限,以後再看,但是我們剛纔開篇註冊的三個Advisor這邊應該是可以拿到的。

	public List<Advisor> findAdvisorBeans() {
		String[] advisorNames = null;
		synchronized (this) {
			advisorNames = this.cachedAdvisorBeanNames;
			//從BeanFactory(或者緩存數組)中拿到advisor的字符串名稱
			if (advisorNames == null) {
				advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
						this.beanFactory, Advisor.class, true, false);
				this.cachedAdvisorBeanNames = advisorNames;
			}
		}
		if (advisorNames.length == 0) {
			return new LinkedList<Advisor>();
		}

		List<Advisor> advisors = new LinkedList<Advisor>();
		for (String name : advisorNames) {
			if (isEligibleBean(name)) {
				if (this.beanFactory.isCurrentlyInCreation(name)) {
					//......................省略
					//進行一些判斷,然後從BeanFactory裏面獲取Advisor實例
					advisors.add(this.beanFactory.getBean(name, Advisor.class));
					}
				}
			}
		}
		return advisors;
	}

3.2 根據找到的所有攔截器,查找合適的攔截器

這一步的操作關鍵的代碼在這邊,我們捨去一些操作,直接來看是怎麼查找ApplyAdvisor的

	AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);

這邊有一種Advisor叫做IntroductionAdvisor ,這個接口網上說好像是類級別上的增強,具體可以查閱對應資料,但是我們這邊不關注這個類.
我們這邊需要關注的是canApply這個方法,因爲他是判斷
Advisor
是否適用於當前事務管理的依據.

	public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
		if (candidateAdvisors.isEmpty()) {
			return candidateAdvisors;
		}
		List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
				eligibleAdvisors.add(candidate);
			}
		}
		boolean hasIntroductions = !eligibleAdvisors.isEmpty();
		for (Advisor candidate : candidateAdvisors) {
			if (candidate instanceof IntroductionAdvisor) {
				// already processed
				continue;
			}
			if (canApply(candidate, clazz, hasIntroductions)) {
				eligibleAdvisors.add(candidate);
			}
		}
		return eligibleAdvisors;
	}

往下看,這邊可以看到,第二個if判斷判斷了類是否是PointcutAdvisor,剛纔上面介紹的BeanFactoryTransactionAttributeSourceAdvisor類就是實現了PointcutAdvisor接口,所以這邊他要起到作用了.
這邊傳入getPointcut方法返回的對象,在上面的介紹中說到,內部實現了TransactionAttributeSourcePointcut
即當前的getPointcut方法傳入TransactionAttributeSourcePointcut

	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}

canApply方法需要關注兩個地方

  • MethodMatcher的獲取
  • 調用matches方法
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}
		
		//MethodMatcher的獲取
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}
		
		//循環通過MethodMatcher的matches方法匹配
		Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		classes.add(targetClass);
		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			for (Method method : methods) {
				if ((introductionAwareMethodMatcher != null &&
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
						methodMatcher.matches(method, targetClass)) {
					return true;
				}
			}
		}

		return false;
	}

4.1 獲取方法匹配器:MethodMatcher

上面說的,傳入的pointcutTransactionAttributeSourcePointcut類,所以直接查看這個類是怎麼獲取MethodMatcher的:

	@Override
	public final MethodMatcher getMethodMatcher() {
		return this;
	}

這邊看到實現的getMethodMatcher方法直接返回this,也就是說,返回的Match就是TransactionAttributeSourcePointcut

4.2 方法匹配器匹配,返回結果

既然我們已經知道了MethodMatcher,就要去看一下matchs到底是怎麼匹配的.

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
			return false;
		}
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

從剛纔的分析可以看到,這邊拿到的TransactionAttributeSourcePointcutBeanFactoryTransactionAttributeSourceAdvisor類中的內部類,並實現了getTransactionAttributeSource方法.
可以參考上面介紹BeanFactoryTransactionAttributeSourceAdvisor,這裏的TransactionAttributeSource注入的是AnnotationTransactionAttributeSource
所以我們來看一下這邊的實現,依然是先通過緩存去獲取,如果沒有獲取到纔去解析。那麼如何解析呢.

	@Override
	public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
		
		Object cacheKey = getCacheKey(method, targetClass);
		Object cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return (TransactionAttribute) cached;
			}
		}
		else {
			TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			if (txAtt == null) {
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				if (logger.isDebugEnabled()) {
					Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass());
					logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." +
							method.getName() + "' with attribute: " + txAtt);
				}
				this.attributeCache.put(cacheKey, txAtt);
			}
			return txAtt;
		}
	}
5.1 解析@Transation註解

這邊的解析分成四種情況,任意一種滿足則退出,方法上的註釋也說明了這些:

  • 解析當前方法上的註解
  • 解析當前類上的註解
  • 解析類實現的接口的方法上的註解
  • 解析類實現的接口上的註解
	protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// Ignore CGLIB subclasses - introspect the actual user class.
		Class<?> userClass = ClassUtils.getUserClass(targetClass);
		// 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 = ClassUtils.getMostSpecificMethod(method, userClass);
		// If we are dealing with method with generic parameters, find the original method.
		specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

		// First try is the method in the target class.
		TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
		if (txAtt != null) {
			return txAtt;
		}

		// Second try is the transaction attribute on the target class.
		txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
			return txAtt;
		}

		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAtt = findTransactionAttribute(method);
			if (txAtt != null) {
				return txAtt;
			}
			// Last fallback is the class of the original method.
			txAtt = findTransactionAttribute(method.getDeclaringClass());
			if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
				return txAtt;
			}
		}

		return null;
	}

解析的步驟不是重點,重點是如何去解析.
可以看到這邊會拿到註解,然後循環查找合適的事務註解去解析並返回.
我們剛纔看到在 AnnotationTransactionAttributeSource中會初始化SpringTransactionAnnotationParser對象

	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
		if (ae.getAnnotations().length > 0) {
			for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
				TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
				if (attr != null) {
					return attr;
				}
			}
		}
		return null;
	}

這邊即通過SpringTransactionAnnotationParser來解析@Trasation註解,看一下代碼即可,不重點分析

	@Override
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
		AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		rbta.setQualifier(attributes.getString("value"));
		ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
		Class<?>[] rbf = attributes.getClassArray("rollbackFor");
		for (Class<?> rbRule : rbf) {
			RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		String[] rbfc = attributes.getStringArray("rollbackForClassName");
		for (String rbRule : rbfc) {
			RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
		for (Class<?> rbRule : nrbf) {
			NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
		for (String rbRule : nrbfc) {
			NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
			rollBackRules.add(rule);
		}
		rbta.getRollbackRules().addAll(rollBackRules);
		return rbta;
	}


2.2 生成代理

上面的步驟結束,已經拿到所有類和方法對應的攔截器數組.即生成代理.
這邊不贅述,參考另一篇博文:Spring代理創建和代理實現

4. 事務攔截器

2.1 需要懂的事務相關的幾個類

3.1 事務信息承載器:TransactionInfo

看一下注釋的內容:

  • Opaque object used to hold Transaction information. Subclasses must pass it back to methods on this class, but not see its internals.

這個類其實是用來承載解析出來的事務屬性集、事務狀態的類。記錄事務的信息主要是在事務執行的生命週期中,Spring可以把控當前事務。他的內部包含了下面幾個類。

	protected final class TransactionInfo {

		private final PlatformTransactionManager transactionManager;

		private final TransactionAttribute transactionAttribute;

		private final String joinpointIdentification;

		private TransactionStatus transactionStatus;

		private TransactionInfo oldTransactionInfo;
}

3.2 事務屬性:TransactionAttribute

剛纔上面的解析器Parse代碼裏面已經說明,這個類是用來承載**@Transaction**註解帶來的屬性的.

3.3 事務狀態:TransactionStatus

這個接口是操作事務最關鍵的類,它能夠實現保存點操作判斷事務狀態等.具體實現在後面的描述中給出
看一下接口上的註釋:

  • programmatically request a rollback (instead of throwing an exception that causes an implicit rollback).
  • Derives from the SavepointManager interface to provide access to savepoint management facilities. Note that savepoint management is only available if supported by the underlying transaction manager.

2.2 事務攔截器實現

事務攔截器實現了MethodInterceptor,上面生成代理的時候會把TransactionInterceptor添加到對應calss的method中.
現在分析一下他的實現:
關注invoke方法:

	@Override
	public Object invoke(final 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, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}

重寫了proceedWithInvocation()方法,調用傳入的MethodInvocation的proceed方法.
可以這樣理解,傳進來的MethodInvoke代表某個正在執行的業務方法或者事務(嵌套事務),那麼事務執行的操作應該是這樣的

{
	事務開始
	try{
		執行業務方法、或者嵌入事務.
	}catch{
		回滾操作
	}finally{
		事務提交、狀態清除等.
	}
}

我們具體看一下代碼:

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		//事務的標識
		final String joinpointIdentification = methodIdentification(method, targetClass);

		//聲明式事務
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			//開啓事務
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			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) {
				//事務回滾
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				//清理操作
				cleanupTransactionInfo(txInfo);
			}
			//事務提交
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			//編程式事務不管
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
						new TransactionCallback<Object>() {
						}
			}
		}
	}

我們從上面代碼可以看到基本是這樣的情況,這邊只分析聲明式事務的處理.

3.1 構造事務信息承載器:TransactionInfo

事務信息承載,最重要的是TransationStatus,所以這邊的代碼分兩個步驟:

  • 獲取TransationStatus
  • 構造TransactionInfo
	protected TransactionInfo createTransactionIfNecessary(
			PlatformTransactionManager tm, 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 {
				//日誌
			}
		}
		//構造TransactionInfo
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

3.2 獲取TransationStatus

這邊通過傳入的TransationAttribute實現事務的管理。分爲三個重要的步驟:拿到事務對象、判斷當前存在事務和不存在事務

@Override
	public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
		//拿到事務對象
		Object transaction = doGetTransaction();
		//存在事務
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		//是否超時
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}
		
		//不存在事務
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				//開始事務
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException ex) {
				resume(null, suspendedResources);
				throw ex;
			}
			catch (Error err) {
				resume(null, suspendedResources);
				throw err;
			}
		}
		else {
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

4.1 拿到事務對象

設置保存點,獲取相應資源

	@Override
	protected Object doGetTransaction() {
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

4.2 存在事務

存在事務的情況,這邊會根據Spring定義的事務的傳播狀態去處理,分別爲:

  • 不支持事務:報錯
  • 執行非事務處理,如果存在的話,暫停當前事務(掛起)
  • 如果新事務的傳播機制是RequireNew,把正在執行的事務掛起.
  • 嵌入式事務
    • 支持設置保存點,創建保存點
    • 不支持設置保存點,掛起當前事務執行新事務

保存點可以通過Connection來處理,這邊不關心底層的實現

	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
		//不支持事務:報錯
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}
		//執行非事務處理,如果存在的話,暫停當前事務(掛起)
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}
		//如果新事務的傳播機制是RequireNew,把正在執行的事務掛起.
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
			catch (Error beginErr) {
				resumeAfterBeginException(transaction, suspendedResources, beginErr);
				throw beginErr;
			}
		}
		//嵌入式事務  支持設置保存點,創建保存點 
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			if (!isNestedTransactionAllowed()) {
				throw new NestedTransactionNotSupportedException(
						"Transaction manager does not allow nested transactions by default - " +
						"specify 'nestedTransactionAllowed' property with value 'true'");
			}
			if (useSavepointForNestedTransaction()) {
				DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
				status.createAndHoldSavepoint();
				return status;
			}
			else {
				//不支持設置保存點,掛起當前事務執行新事務
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, null);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
		}
		//..............略
	}
5.1 設置Spring管理Connection及屬性

doBegin方法獲取連接,交由Spring管理,主要關注DataSourceTransactionManager這個類的具體實現包括下面幾個部分:

  • 嘗試獲取連接,獲取不到則創建連接
  • 設置事務隔離級別
  • 更改自動提交設置,將提交給Spring實現
  • 激活事務、設置超時時間
  • 將連接綁定到當前線程
  • 如果異常,釋放連接
    @Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
            //嘗試獲取連接,獲取不到則創建連接
            if (txObject.getConnectionHolder() == null || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                Connection newCon = this.dataSource.getConnection();
              	txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }
            txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
            con = txObject.getConnectionHolder().getConnection();
			//設置事務隔離級別
            Integer previousIsolationLevel = org.springframework.jdbc.datasource.DataSourceUtils.prepareConnectionForTransaction(con, definition);
            txObject.setPreviousIsolationLevel(previousIsolationLevel);
			//更改自動提交設置,將提交給Spring實現
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                con.setAutoCommit(false);
            }
            //激活事務、設置超時時間
            txObject.getConnectionHolder().setTransactionActive(true);
            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            if (txObject.isNewConnectionHolder()) {
                //將連接綁定到當前線程
                TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
            }
        }
        catch (Throwable ex) {
            if (txObject.isNewConnectionHolder()) {
               	//異常釋放連接
                org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection(con, this.dataSource);
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }
5.2 將事務信息記錄到事務隊列管理器
    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();
        }
    }

4.3 不存在事務

5.1 設置Spring管理Connection及屬性

同上

5.2 將事務信息記錄到事務隊列管理器

同上

3.3 構造TransactionInfo

這邊比較關鍵的一步就是綁定事務到線程.從註釋上面看,是爲了正確管理,即使沒有創建事務的情況。
而bindToThread其實是維護了一個ThreadLocal的變量。

	 */
	protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
			TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
		
		//構造TransactionInfo 
		TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
		if (txAttr != null) {
			txInfo.newTransactionStatus(status);
		}
		else {
			//日誌
		}

		// 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;
	}

2.3 執行相應業務方法

這一步就是方法的調用,沒有特別指的分析的地方:

	return invocation.proceedWithInvocation();
	return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
	});

2.4 事務異常處理

事務異常分成兩種情況,如果拋出RunTimeExceptionError直接回滾,其他異常會嘗試提交

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
        /**
         * 57.當拋出異常時首先判斷當前是否存在事務,這是基本依據
         */
        if (txInfo != null && txInfo.hasTransaction()) {
           	//對於RunTimeException或Error的異常會終止提交
            if (txInfo.transactionAttribute.rollbackOn(ex)) {
                try {
                    //回滾操作
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                }
                catch (TransactionSystemException ex2) {.//.....略
                }
            }
           	//其他的異常依然會操作提交
            else {
                try {
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                }
                catch (TransactionSystemException ex2) {
                  //........略}
            }
        }
    }

3.1 事務回滾

事務回滾會先判斷狀態,如果已經提交(有這種情況?),直接報錯,不然利用Connection的Api處理回滾

    @Override
    public final void rollback(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;
        //處理回滾
        processRollback(defStatus);
    }

回滾分成幾種情況

  • 通過保存點進行回滾
  • 新事務通過Connection的api調用回覆
  • 其他則設值回滾標識
  • 事務處理結束之後的信息清除
    private void processRollback(DefaultTransactionStatus status) {
        try {
            try {
                /**
                 * 自定義觸發器的調用,註冊參考
                 * @see TransactionSynchronizationManager#registerSynchronization(TransactionSynchronization)
                 */
                triggerBeforeCompletion(status);
               //通過保存點信息進行回滾
                if (status.hasSavepoint()) {
                    status.rollbackToHeldSavepoint();
                }
                //如果是新的事務,直接回滾,這邊也是通過Connection回滾
                else if (status.isNewTransaction()) {
                    doRollback(status);
                }
                else if (status.hasTransaction()) {
                    if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
                 		//標記爲回滾狀態,下一次執行的時候回滾
                        doSetRollbackOnly(status);
                    }
                    else {
                       //..............
                       }
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
        }
        finally {
            //事務處理結束之後的信息清除
            cleanupAfterCompletion(status);
        }
    }

通過保存點回滾也是直接調用Connection的api,如下:

  //從保存點回滾
  conHolder.getConnection().rollback((Savepoint) savepoint);
   //釋放保存點
  conHolder.getConnection().release((Savepoint) savepoint);

事務處理結束之後的信息清除和事務提交之後的finally操作一樣,這邊不贅述,往後看

2.5 TransactionInfo清除

重置TransactionInfo

    /**
     * Reset the TransactionInfo ThreadLocal.
     * <p>Call this in all cases: exception or normal return!
     */
    protected void cleanupTransactionInfo(TransactionInfo txInfo) {
        if (txInfo != null) {
            txInfo.restoreThreadLocalStatus();
        }
    }

2.6 事務提交

事務提交這邊也分爲幾種情況:

  • 事務已經提交,報錯
  • 標記爲回滾,調用回滾方法(回滾方法中有一步處理就是設置這個標識)
  • 提交
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()) {
            processRollback(defStatus);
            return;
        }
        if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
            processRollback(defStatus);
            if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
                throw new UnexpectedRollbackException(
                    "Transaction rolled back because it has been marked as rollback-only");
            }
            return;
        }

      	//處理事務提交
        processCommit(defStatus);
    }

這邊主要分成幾步:

  • 存在保存點,說明有事務沒有執行完不提交
  • 如果是新事務,說明事務執行完成了,調用Connectio.commit提交事務
  • 其他情況不提交,報錯回滾或者拋錯
  • finally清除操作
    private void processCommit(DefaultTransactionStatus status) throws TransactionException {
        try {
            boolean beforeCompletionInvoked = false;
            try {
                prepareForCommit(status);
                triggerBeforeCommit(status);
                triggerBeforeCompletion(status);
                beforeCompletionInvoked = true;
                boolean globalRollbackOnly = false;
                if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
                    globalRollbackOnly = status.isGlobalRollbackOnly();
                }
                if (status.hasSavepoint()) {
                  //存在保存點則清除,但不提交事務
                  status.releaseHeldSavepoint();
                }
                else if (status.isNewTransaction()) {
                    //獨立新事務的提交---非獨立新事物不提交
                    doCommit(status);
                }
               
            try {
                triggerAfterCommit(status);
            }
            finally {
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
            }

        }
        finally {
            /**
             * 83.提交後清除操作
             */
            cleanupAfterCompletion(status);
        }
    }

finally清除操作主要分成下面幾步:

  • 修改事務狀態
  • 新事務連接釋放
  • 如果有事務被掛起,則喚醒對應事務
  private void cleanupAfterCompletion(DefaultTransactionStatus status) {
        //修改事務狀態
        status.setCompleted();
        if (status.isNewSynchronization()) {
            //清除當前事務的同步信息
            TransactionSynchronizationManager.clear();
        }
        if (status.isNewTransaction()) {
            //事務連接釋放
            doCleanupAfterCompletion(status.getTransaction());
        }
       	//如果當前事務執行前有事務被掛起,這邊是設置一個Object的屬性,這也是事務傳播的一個處理
        if (status.getSuspendedResources() != null) {
            //恢復前一個掛起的事務
            resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
        }
    }
發佈了84 篇原創文章 · 獲贊 15 · 訪問量 3200
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章