spring聲明式事務@Transactional底層工作原理
引言
寫這篇博文有個來由,是為了解決博主遇到的多數據源的事務問題(用不了JTA),所以深入到spring-tx的源碼去學習了一番,非常有收獲,最后博主的分布式事務問題也迎刃而解了,這個文章算個開篇,關于如何處理多數據源事務,待下文分解。本文涉及到的技術包含spring aop的使用、spring bean生命周期等,如果能夠真正理解Transactional的工作原理,對排查事務相關的問題有非常大的幫助。
spring-tx版本:5.0.2
工作機制簡述
先來看一張官方的事務簡圖:

spring定義了@Transactional注解,基于AbstractBeanFactoryPointcutAdvisor、StaticMethodMatcherPointcut、MethodInterceptor的aop編程模式,增強了添加@Transactional注解的方法。同時抽象了事務行為為PlatformTransactionManager(事務管理器)、TransactionStatus(事務狀態(tài))、TransactionDefinition(事務定義)等形態(tài)。最終將事務的開啟、提交、回滾等邏輯嵌入到被增強的方法的前后,完成統一的事務模型管理。
事務AOP核心類釋義
@Transactional
事務注解,用于定位aop的切入點,事務注解里包含了完整事務的所有基本屬性,常見的屬性如:
transactionManager:事務管理器
propagation:傳播行為定義,枚舉類型,是spring獨有的事務行為設計,默認為PROPAGATION_REQUIRED(支持當前事務,不存在則新建)
isolation:隔離級別,對應數據庫的隔離級別實現,mysql默認的隔離級別是 read-committed
timeout:超時時間,默認使用數據庫的超時,mysql默認的事務等待超時為5分鐘
readOnly:是否只讀,默認是false
rollbackFor:異?;貪L列表,默認的是RuntimeException異?;貪L
TransactionAttribute
事務屬性抽象接口類,承載了@Transactional注解里的所有屬性,實現類的繼承關系如下類結構圖,這個實例在被注解解析器創(chuàng)建好后,會在事務上下文中傳遞

SpringTransactionAnnotationParser
見名知意,這個類是spring的事務注解解析器,實現自TransactionAnnotationParser接口,是spring管理的事務解析器,用于解析@Transactional注解,將注解里的屬性設置到TransactionAttribute的實現類屬性里。除了這個,另還有兩個實現,分別是JTA事務注解解析器,和EJB事務注解管理解析器,區(qū)別是解析的注解不同,spring是@Transactional,jta是javax.transaction.Transactional,EJB是javax.ejb.TransactionAttribute。這個地方應用和apache dubbo2.7.x版本解析dubbo的@service注解是一樣一樣的。關鍵代碼如下,通過AnnotatedElementUtils類,這個類在spring-core包下,找到注解屬性集AnnotationAttributes,如果不為空,則包裝成事務屬性集返回
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}AnnotationTransactionAttributeSource
見名知意,這個類是注解事務屬性集的源,怎么理解呢?spring抽象了獲取事務屬性集的行為,而AnnotationTransactionAttributeSource正是@Transactional注解方式的事務屬性集收集實現。SpringTransactionAnnotationParser就是作用于這個里面,用于發(fā)現@Transactiona注解的方法
TransactionAttributeSourcePointcut
也是見名知意,Pointcut屬于aop的概念范疇,需要了解spring aop的知識才能看明白,這個就是@Transactional注解的切點,AnnotationTransactionAttributeSource作用于此,用于尋找@Transactiona注解的方法,關鍵代碼如下:
public boolean matches(Method method, Class targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}TransactionInterceptor
事務的攔截器。aop編程里,有了切入點Pointcut,就要有通知advice,我們熟悉的spring aop里有前置、后置、環(huán)繞、異常等通知類型,TransactionInterceptor屬于自定義通知模型實現,實現自Advice接口,類似于環(huán)繞通知,具體見類結構圖,如下:

核心方法如下:
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);
}被@Transactional注解的方法,如果被aop正確的增強了,運行的時候都會進入到這個方法里面,如果你發(fā)現事務不生效啊等等問題,可以從這里開始定位真實原因
BeanFactoryTransactionAttributeSourceAdvisor
事務增強器,用于增強添加了@Transactional注解的方法,上面提到的這些核心類,最終都作用于這里,用于尋找@Transactional注解的方法和織入事務處理邏輯
ProxyTransactionManagementConfiguration
代理事務管理的配置類,上面介紹的這些事務aop編程相關的在這個里面組合配置生效的,同時,如果你有特殊的個性化的需求,也可以自定義注冊這個里面的實例。比如我嫌棄@Transactional注解太長了,想用@Tx注解。沒關系,直接定義個TransactionAttributeSource實現,解析@Tx的方法,然后注冊到spring的上線文中即可。代碼如:
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(
TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}事務抽象核心類釋義
PlatformTransactionManager
平臺事務管理器,這是Spring事務基礎設施中的中心接口。它定義了三個最最基本的事務方法,getTransaction獲取事務,包含了事務開啟的行為,commit提交事務,rollback回滾事務。代碼如下:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}在spring-tx中并沒有提供真正的實現類,只提供了一個抽象派生類AbstractPlatformTransactionManager,并建議其他實現基于這個派生類,因為它預先實現了定義的傳播行為并處理事務同步處理。子類必須為底層事務的特定狀態(tài)實現模板方法,例如:begin、suspend、resume、commit等。我們平時常見的實現有:JpaTransactionManager、JtaTransactionManager、DataSourceTransactionManager等。事務管理器和事務aop處理的邏輯本身沒有任何耦合,只需將PlatformTransactionManager實例注冊到spring上下文中即可,事務攔截器會通過獲取到@Transactional里的transactionManager屬性去上下文中尋找事務管理器,并將其緩存起來,見TransactionAspectSupport.java里的determineTransactionManager方法
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return asPlatformTransactionManager(getTransactionManager());
}
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager(getTransactionManager());
if (defaultTransactionManager == null) {
defaultTransactionManager = asPlatformTransactionManager(
this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY));
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}TransactionStatus
事務狀態(tài)抽象,用這個類的實現來維護當前的事務狀態(tài),spring-tx里提供了默認的實現DefaultTransactionStatus。一般情況下這個不需要我們關心,它和PlatformTransactionManager是成對存在的,心細的你可能已經發(fā)現了,PlatformTransactionManager里的三個事務行為傳遞的就是TransactionStatus。我們知道事務aop增強了添加@Transactional的方法,在執(zhí)行方法前調用PlatformTransactionManager.getTransaction開啟事務,之后調用commit方法提交事務,提交事務的入參TransactionStatus就是開啟事務獲得的。參見TransactionAspectSupport.java里的createTransactionIfNecessary方法
TransactionDefinition
事務定義,對應了TransactionAttribute,最終通過aop得到的TransactionAttribute里的屬性會被傳遞到TransactionDefinition里,所以TransactionDefinition里也包含了所有事務相關的屬性,PlatformTransactionManager.getTransaction正是通過這個里面的屬性去獲取的事務。AbstractPlatformTransactionManager派生類里也是通過這個里面的屬性去判斷協調spring的事務傳播行為的
結語
當梳理完spring-tx模塊的整個結構和工作方式后,仿佛拉開了spring事務管理的面紗,很多事務的執(zhí)行細節(jié)一覽無余。很多事務相關的問題也就很容易解釋了。比如常見的類中的方法直接調用方法事務不生效等問題,以及可以非常清晰的理解spring的傳播行為的真正含義等。最后預告下,spring對于多數據源的事務處理解決方案ChainedTransactionManager
以上就是spring聲明式事務@Transactional底層工作原理的詳細內容,更多關于spring聲明式事務@Transactional工作原理的資料請關注腳本之家其它相關文章!
相關文章
詳解Spring boot+CXF開發(fā)WebService Demo
這篇文章主要介紹了詳解Spring boot+CXF開發(fā)WebService Demo,非常具有實用價值,需要的朋友可以參考下2017-05-05
淺談Java中實現深拷貝的兩種方式—clone() & Serialized
這篇文章主要介紹了Java中實現深拷貝的兩種方式—clone() & Serialized,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03
Java的Hibernate框架中集合類數據結構的映射編寫教程
Hibernate可以將Java中幾個內置的集合結構映射為數據庫使用的關系模型,下面我們就來看一下Java的Hibernate框架中集合類數據結構的映射編寫教程:2016-07-07

