【Spring源碼分析】六、Spirng transaction分析

一、tx的解析和bean的Aop代理

<tx:annotation-driven transaction-manager="transactionManager"/>
  • 針對namespace就行判斷,判斷是bean標籤還是自定義標籤(除了bean的其他標籤)
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(root)) {
			NodeList nl = root.getChildNodes();
			for (int i = 0; i < nl.getLength(); i++) {
				Node node = nl.item(i);
				if (node instanceof Element) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

這個毫無疑問是進入delegate.parseCustomElement(ele); 這裏面進行自定義標籤的解析

  • 獲取對應namespace的處理器
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

在這裏插入圖片描述
通過分析,tx的解析器是TxNamespaceHandler

  • 獲取annotation-driven的解析器
    handler.parse中首選就是獲取對應的解析器
public BeanDefinition parse(Element element, ParserContext parserContext) {
		BeanDefinitionParser parser = findParserForElement(element, parserContext);
		return (parser != null ? parser.parse(element, parserContext) : null);
	}

private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
		String localName = parserContext.getDelegate().getLocalName(element);
		BeanDefinitionParser parser = this.parsers.get(localName);
		if (parser == null) {
			parserContext.getReaderContext().fatal(
					"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
		}
		return parser;
	}

在這裏插入圖片描述
最終得知是AnnotationDrivenBeanDefinitionParser進行解析。

  • 開始真正的解析
public BeanDefinition parse(Element element, ParserContext parserContext) {
		registerTransactionalEventListenerFactory(parserContext);
		String mode = element.getAttribute("mode");
		//沒想到spring也會直接寫某個字符串(印象中都是通過一個static變量進行定義的)
		if ("aspectj".equals(mode)) {
			// mode="aspectj"
			registerTransactionAspect(element, parserContext);
			if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
				registerJtaTransactionAspect(element, parserContext);
			}
		}
		else {
			// mode="proxy"
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}
  • 註冊和事務有關的BeanPostProcessor和事務有關的攔截器等

保留核心代碼

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

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

				// Create the TransactionAttributeSource definition.(事務的屬性配置)
				RootBeanDefinition sourceDef = new RootBeanDefinition(						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				
				// Create the TransactionInterceptor definition.(事務方法攔截器)
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);			

				// Create the TransactionAttributeSourceAdvisor definition.(這就是一個advisor,一個advisor可以包含一個攔截器)
				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);
			}
		}

從這裏就可以看出來spring的事務管理其實就是Aop的一個典型應用
點擊AOP源碼分析 ,來獲取更詳細的信息

  1. advisorDef :從aop的源碼分析可知,一個advisor可看成是一個應用pointCut的通知(類似前置或者後置等通知),創建單例的時候比如JDK代理,會有一個invocationHandler(或者說Cglib會又至少一個callback),在這裏其實TransactionInterceptor 就是真正的攔截實現類
  2. TransactionInterceptor :真正的攔截實現類
  3. TransactionAttributeSource:這個就是解析xml或者annotation中的配置
    重點分析一下TransactionAttributeSource
    在這裏插入圖片描述
    它的核心邏輯是存在AbstractFallbackTransactionAttributeSource中的getTransactionAttribute方法中
//getTransactionAttribute會調用這個方法
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 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;
	}

簡單來說會從目標類的方法上需要事務註解,如果沒有找到就從接口中去尋找。

現在advisor有了,但是還缺少一個生成代理的契機,比如某個切面的pointcut命中了某個bean,在哪個bean初始化後,在AnotationAwareAspectJAutoProxyCreator後置處理器的postProcessAfterInitialization方法中就創建了這個bean的代理。
現在我們也缺少一個後置處理器。其實這上面這個 方法的第一句話

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

就是做這樣的事情

public static void registerAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {

		BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(				
	}

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

最後發現InfrastructureAdvisorAutoProxyCreator出現了這個類,和AnotationAwareAspectJAutoProxyCreator有些類似
在這裏插入圖片描述
分析UML圖後發現確實是個BeanPostProcessor。好了到了這裏Spring事務的bean的代理生成已經分析完畢。

二、事務攔截器的分析

切入點是TransactionInterceptor

public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

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);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
		
		//聲明式事務(編程式事務我刪除了)
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {

			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

			Object retVal;
			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);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
}
  1. tas: 這個就是前面解析的時候的TransactionAttributeSource
  2. tm :這個就比較複雜了。先看PlatformTransactionManagerUML圖
    在這裏插入圖片描述
    頂級接口PlatformTransactionManager是jdbc事務管理和jta事務的頂級接口。大部分邏輯是在AbstractPlatformTransactionManager就完成了,剩下的一些模板方法就是在DataSourceTransactionManagerJtaTransactionManager中的doxxx方法中。

DataSourceTransactionManager:基本可以看出是單一數據庫的事務管理
JtaTransactionManager:多數據庫的事務管理器,他還有另外一個高大上的名字分佈式事務的實現
下面重點分析下面這句話

TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

從名字上看如果需要就創建事務信息,如果不需要就利用當前線程已經存在的事務。

方法createTransactionIfNecessary主要是調用getTransaction方法

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}

		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// No existing transaction found -> check propagation behavior to find out how to proceed.
		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 | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}

在方法doGetTransaction

protected Object doGetTransaction() {
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());//核心就是這句話
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

在TransactionSynchronizationManager.getResource(obtainDataSource())中就是獲取數據庫的連接了。

getResource方法主要是利用ThreadLocal變量獲取連接

private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");

這樣如果當前線程已經存在線程,肯定可以從當前線程獲取到jdbc的連接,這樣新的事務和老的事務就公用了一個connection了。這就是傳播行爲Propagation.REQUIRED把兩個事務合成一個事務就行管理的關鍵了,也很容易理解回滾的時候,可以同時回滾了,因爲利用的是同一個connnection。

未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章