前言
事務我們都知道是什么脊凰,而Spring事務就是在數據庫之上利用AOP提供聲明式事務和編程式事務幫助我們簡化開發(fā),解耦業(yè)務邏輯和系統(tǒng)邏輯茂腥。但是Spring事務原理是怎樣狸涌?事務在方法間是如何傳播的?為什么有時候事務會失效础芍?接下來幾篇文章將重點分析Spring事務源碼杈抢,讓我們徹底搞懂Spring事務的原理。
XML標簽的解析
<tx:annotation-driven transaction-manager="transactionManager"/>
配置過事務的應該都不陌生仑性,上面這個配置就是Spring開啟事務注解(@Transactional)支持的配置,而看過我之前文章的應該知道右蹦,這個帶前綴的標簽叫自定義標簽诊杆,我在之前的文章也分析過自定義標簽的解析過程,所以這里我直接找到對應的handler:
public class TxNamespaceHandler extends NamespaceHandlerSupport {
static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
static String getTransactionManagerName(Element element) {
return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
}
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}
}
可以看到對應的注解解析器就是 AnnotationDrivenBeanDefinitionParser 類何陆,在該類中一定會有一個 parse 方法:
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
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;
}
首先拿到 mode 屬性的值判斷是使用AspectJ生成代理還是JDK生成代理晨汹,這里我們主要看 proxy 模式,進入 configureAutoProxyCreator 方法:
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 注冊AOP的入口類
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.
// @Transactional注解的屬性封裝
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// Create the TransactionInterceptor definition.
// AOP執(zhí)行鏈
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 拿到transaction-manager屬性的值
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// Create the TransactionAttributeSourceAdvisor definition.
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);
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);
}
}
這里的流程比較長贷盲,但邏輯很簡單淘这。首先來看注冊事務AOP入口類是哪個:
public static void registerAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 將優(yōu)先級更高的AOP入口類放入到IOC容器中
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 設置代理生成的方式以及是否緩存代理類到當前線程
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
主要看 registerAutoProxyCreatorIfNecessary 方法:
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
// 判斷傳進來的類和ICO中當前存在的類哪個優(yōu)先級更高,將更高的放入IOC中
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//把AOP入口類封裝成beanDefinition對象巩剖,要實例化
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//注解aop入口類的beanName名稱 AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
首先判斷容器中是否已經存在AOP入口類铝穷,如果不存在則直接創(chuàng)建
InfrastructureAdvisorAutoProxyCreator的BeanDefinition對象注冊到容器中,這個類也是AOP入口類AbstractAutoProxyCreator的子類佳魔,再來看看其繼承關系:
你會不會疑惑鞠鲜,這么多子類宁脊,到底會使用哪一個呢?回到剛剛的代碼中贤姆,可以看到如果已經存在一個入口類了榆苞,就會通過 findPriorityForClass 獲取兩個類的優(yōu)先級,最終就會使用優(yōu)先級更大的那個霞捡,那么它們的優(yōu)先級順序是怎樣的呢坐漏?
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
private static int findPriorityForClass(@Nullable String className) {
// 索引即是優(yōu)先級,越大優(yōu)先級越高,IOC中只會存在一個事務AOP入口類
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
throw new IllegalArgumentException(
"Class name [" + className + "] is not a known auto-proxy creator class");
}
可以看到仙畦,
InfrastructureAdvisorAutoProxyCreator是優(yōu)先級最低的输涕,基本上不會起作用;AspectJAwareAdvisorAutoProxyCreator是當我們配置了<aop:config>標簽時會注冊慨畸,也就是xml配置的AOP的入口類莱坎;而AnnotationAwareAspectJAutoProxyCreator是當我們配置了<aop:aspectj-autoproxy>或使用@EnableAspectJAutoProxy注解時注冊,因此大部分情況下都是使用的AnnotationAwareAspectJAutoProxyCreator寸士。
注冊完AOP的入口類后檐什,回到configureAutoProxyCreator方法:
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName =parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
AnnotationTransactionAttributeSource類的作用就是封裝事務注解@Transactional的屬性,這里需要記住其繼承體系以及熟悉該類和其父類的屬性和方法弱卡,對后面分析事物切面執(zhí)行原理有幫助:
緊接著就是創(chuàng)建了TransactionInterceptor對象婶博,專門的事務攔截器瓮具,并且該類是MethodInterceptor的子類,看到這個應該不陌生了凡人,我們知道AOP調用鏈在執(zhí)行過程中主要就是調用該類的invoke的方法名党,因此它是事務切面執(zhí)行的入口。既然有了Interceptor挠轴,那么必不可少的還應該有Advisor传睹,而Advisor又是由Advice和Poincut組成的,這樣才能構成一個完整的切面岸晦,所以該方法后面就是創(chuàng)建這兩個對象欧啤。以上就是xml配置AOP注解支持的原理,很簡單启上,下面再來看看零配置又是如何實現的邢隧。
AOP零配置原理
使用過SpringBoot的都知道,如果需要開啟事務注解的支持碧绞,只需要一個注解就能搞定:@
EnableTransactionManagement府框,不用再配置xml文件,這個又是怎么做到的呢讥邻?不多說迫靖,我們直接來看其源碼:
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
在該注解下使用@Import導入了一個類
TransactionManagementConfigurationSelector,首先該注解的作用就是導入一個類的實例到IOC容器中兴使,你可能會說不是在類上加@Component注解就行了么系宜,但是有些類它并不在你掃描的路徑下,而該注解依然可以將其導入進來发魄,所以我么主要看TransactionManagementConfigurationSelector類中做了些啥:
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[] {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);
}
}
可以看到在selectImports方法中返回了AutoProxyRegistrar和
ProxyTransactionManagementConfiguration類盹牧,返回后會被封裝為BeanDefinition對象俩垃,那這個方法是在哪里調用的呢?這個在之前的文章中也分析過汰寓,ConfigurationClassPostProcessor類中會調用ConfigurationClassParser類的parse方法解析@Configuration口柳、@Import、@ImportSource等注解有滑,具體過程這里就不再贅述了跃闹。我們繼續(xù)來分別看看AutoProxyRegistrar和ProxyTransactionManagementConfiguration類:
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@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);
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) {
//注冊事務AOP的入口類InfrastructureAdvisorAutoProxyCreator,實際上這個AOP入口類起不了作用
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
}
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/*
* 明顯是創(chuàng)建事務切面實例
* BeanFactoryTransactionAttributeSourceAdvisor
*
* */
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
//設置通知類
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/*
* 創(chuàng)建事務advice
* TransactionInterceptor
* */
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
//事務管理器要跟數據源掛鉤,所以需要自己定義
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
看到這就很清楚了毛好,前者是注冊AOP的入口類(這里注冊的入口類依然是
InfrastructureAdvisorAutoProxyCreator)望艺,后者則是創(chuàng)建事務AOP的組件的實例到IOC中,到這里相信不僅僅是對于事務的零配置肌访,而是整個SpringBoot的零配置實現原理都心中有數了找默。