前言
spring boot 的自動化配置其實就是在spring 的基礎上作的封裝,在咱們以前對mvc,aop的自動化配置中能夠發現–> 只是在spring 的基礎上添加了一些特性,能夠認爲只是一個spring的應用.那麼,關於transaction的配置也一樣.spring
解析
和aop自動配置同樣,在/META-INF/spring.factories中配置有關transaction的有2個:mvc
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration
咱們這裏只分析 TransactionAutoConfigurationapp
TransactionAutoConfiguration 聲明瞭以下註解:ide
@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
1
2
3
4
5
6
@Configuration–>配置類
@ConditionalOnClass(PlatformTransactionManager.class)–> 當前類路徑下存在PlatformTransactionManager.class 時該配置生效
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class })–> 在JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,Neo4jDataAutoConfiguration.class 以後才解析該類.
@EnableConfigurationProperties(TransactionProperties.class)–> 可經過如下2個屬性來配置:函數
spring.transaction.defaultTimeout–> 配置事務的默認超時時間
spring.transaction.rollbackOnCommitFailure–> 配置是否在事務提交失敗時回滾
在 spring boot 源碼解析11-ConfigurationClassPostProcessor類加載解析 中 咱們知道了spring boot 解析配置的類的屬性,對於當前來講,因爲TransactionAutoConfiguration有2個內部類,所以會處理內部類:ui
TransactionTemplateConfiguration, 其註解以下:this
@Configuration
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
1
2
@Configuration –> 配置類
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)–> 當PlatformTransactionManager類型的bean存在而且當存在多個bean時指定爲Primary的PlatformTransactionManager存在時,該配置類才進行解析
因爲TransactionAutoConfiguration是在DataSourceTransactionManagerAutoConfiguration以後才被解析處理的,而在DataSourceTransactionManagerAutoConfiguration中配置了transactionManager,所以, TransactionTemplateConfiguration 會被處理..net
TransactionTemplateConfiguration只有一個被@Bean註解的方法,代碼以下:debug
@Bean
@ConditionalOnMissingBean
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(this.transactionManager);
}
1
2
3
4
5
當beanFactory中不存在TransactionTemplate類型的bean時,註冊一個id爲transactionTemplate,類型爲TransactionTemplate的bean代理
EnableTransactionManagementConfiguration,註解以下:
@Configuration
@ConditionalOnBean(PlatformTransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
1
2
3
@Configuration –> 配置類
@ConditionalOnBean(PlatformTransactionManager.class) –> 當beanFactory中存在PlatformTransactionManager類型的bean時該配置生效
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)–> 當beanFactory不存在AbstractTransactionManagementConfiguration類型的bean時生效.
因爲EnableTransactionManagementConfiguration只有內部類,一樣首先解析內部類:
JdkDynamicAutoProxyConfiguration:
@Configuration
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
1
2
3
4
5
@Configuration–> 配置類
@EnableTransactionManagement(proxyTargetClass = false)–>啓用TransactionManagement, proxyTargetClass = false,表示是面向接口代理.關於這個註解,咱們後面會分析.
@ConditionalOnProperty(prefix = 「spring.aop」, name = 「proxy-target-class」, havingValue = 「false」, matchIfMissing = false)–> 配置有spring.aop.proxy-target-class = false時生效,若是沒配置,則不生效
CglibAutoProxyConfiguration,代碼以下:
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
1
2
3
4
5
@Configuration–> 配置類
@EnableTransactionManagement(proxyTargetClass = true)–>啓用TransactionManagement, proxyTargetClass = true,表示是使用cglib進行代理.關於這個註解,咱們後面會分析.
@ConditionalOnProperty(prefix = 「spring.aop」, name = 「proxy-target-class」, havingValue = 「true」, matchIfMissing = true)–> 配置有spring.aop.proxy-target-class = true時生效,若是沒配置,則默認生效
所以,在默認狀況下,EnableTransactionManagementConfiguration 生效的是JdkDynamicAutoProxyConfiguration.
@EnableTransactionManagement 註解以下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// false--> jdk動態代理,true-->cglib代理,默認使用的是jdk動態代理
boolean proxyTargetClass() default false;
// 代表transactional 切面是如何織入的,默認是代理
AdviceMode mode() default AdviceMode.PROXY;
// aop的優先級
int order() default Ordered.LOWEST_PRECEDENCE;
}
1
2
3
4
5
6
7
8
9
10
11
12
該註解經過@Import(TransactionManagementConfigurationSelector.class)註解導入了TransactionManagementConfigurationSelector,類圖以下:
所以會調用TransactionManagementConfigurationSelector#selectImports.代碼以下:
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;
}
}
1
2
3
4
5
6
7
8
9
10
若是是AdviceMode.PROXY,返回org.springframework.context.annotation.AutoProxyRegistrar,org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
若是是AdviceMode.ASPECTJ,返回org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration
不然,返回null
此時,因爲傳入的是AdviceMode.PROXY,所以執行第1步
接着,將第一步的返回值傳入processImports中繼續調用.
因爲AutoProxyRegistrar實現了ImportBeanDefinitionRegistrar接口,所以會將其實例化後,加入到JdkDynamicAutoProxyConfiguration所對應的ConfigurationClass中的importBeanDefinitionRegistrars
ProxyTransactionManagementConfiguration類既不是ImportSelector的子類也不是ImportBeanDefinitionRegistrar的子類,所以會調用ConfigurationClassParser#processConfigurationClass處理.該類的類圖以下:
因爲AbstractTransactionManagementConfiguration實現了ImportAware接口.所以會調用其setImportMetadata方法.代碼以下:
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableTx = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
if (this.enableTx == null) {
throw new IllegalArgumentException(
"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
}
}
1
2
3
4
5
6
7
8
從@EnableTransactionManagement 中獲取配置信息,封裝爲AnnotationAttributes.若是@EnableTransactionManagement沒有配置屬性的話,就會返回null,此時就會拋出IllegalArgumentException.
同時在AbstractTransactionManagementConfiguration聲明瞭一個被@Autowired(required = false)註解的方法:
@Autowired(required = false)
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
if (configurers.size() > 1) {
throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
}
TransactionManagementConfigurer configurer = configurers.iterator().next();
this.txManager = configurer.annotationDrivenTransactionManager();
}
1
2
3
4
5
6
7
8
9
10
11
當得到該bean時,會將beanFactory中全部TransactionManagementConfigurer類型獲得bean傳遞給該函數
若是configurers爲空,直接return
若是有多個TransactionManagementConfigurer類型的bean,則拋出IllegalStateException
得到PlatformTransactionManager
注意: TransactionManagementConfigurer在spring 中沒有實現,所以正常狀況下是不會有TransactionManagementConfigurer類型的bean
同時在AbstractTransactionManagementConfiguration中註冊了一個id爲org.springframework.transaction.config.internalTransactionalEventListenerFactory,類型爲TransactionalEventListenerFactory,角色爲內部使用的bean,代碼以下:
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
1
2
3
4
5
6
ProxyTransactionManagementConfiguration中很簡單了,聲明瞭3個bean,分別以下:
id 爲org.springframework.transaction.config.internalTransactionAdvisor,類型爲BeanFactoryTransactionAttributeSourceAdvisor,角色爲內部使用的bean.代碼以下:
@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;
}
1
2
3
4
5
6
7
8
9
實例化BeanFactoryTransactionAttributeSourceAdvisor
配置 transactionAttributeSource
配置 Advice–>切面
配置aop優先級–>默認Integer.MAX_VALUE
id爲transactionAttributeSource,類型爲TransactionAttributeSource,角色爲內部使用的bean.代碼以下:
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
1
2
3
4
5
id爲transactionInterceptor,類型爲TransactionInterceptor,角色爲內部使用的bean.代碼以下:
@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;
}
1
2
3
4
5
6
7
8
9
10
視線回到TransactionAutoConfiguration,內部類處理完以後,因爲TransactionAutoConfiguration聲明瞭@EnableConfigurationProperties(TransactionProperties.class) 註解,而@EnableConfigurationProperties註解經過@Import(EnableConfigurationPropertiesImportSelector.class)引入了EnableConfigurationPropertiesImportSelector.
所以,接下來會調用ConfigurationClassParser#processImports
因爲EnableConfigurationPropertiesImportSelector是ImportSelector的實現,調用其selectImports方法返回的是ConfigurationPropertiesBeanRegistrar,ConfigurationPropertiesBindingPostProcessorRegistrar.
因爲ConfigurationPropertiesBeanRegistrar, ConfigurationPropertiesBindingPostProcessorRegistrar是ImportBeanDefinitionRegistrar的實現,添加到TransactionAutoConfiguration對應的importBeanDefinitionRegistrars中.
接着,處理TransactionAutoConfiguration中被@bean註解的方法—> 只有一個,代碼以下:
@Bean
@ConditionalOnMissingBean
public TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider<List<PlatformTransactionManagerCustomizer<?>>> customizers) {
return new TransactionManagerCustomizers(customizers.getIfAvailable());
}
1
2
3
4
5
6
TransactionAutoConfiguration 配置類解析完以後,會調用ConfigurationClassBeanDefinitionReader#loadBeanDefinitions.會依次處理TransactionAutoConfiguration配置類中生成的ConfigurationClass
ProxyTransactionManagementConfiguration 對應的ConfigurationClass,因爲是被JdkDynamicAutoProxyConfiguration導入的,所以會調用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法,代碼以下:
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata();
AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
configBeanDef.setScope(scopeMetadata.getScopeName());
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
configClass.setBeanName(configBeanName);
if (logger.isDebugEnabled()) {
logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
向BeanDefinitionRegistry進行註冊.
同時,因爲在ProxyTransactionManagementConfiguration中定義了4個@bean方法,所以會依次調用loadBeanDefinitionsForBeanMethod進行註冊.
JdkDynamicAutoProxyConfiguration 是被EnableTransactionManagementConfiguration導入,所以一樣會調用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法,進行註冊.
因爲在JdkDynamicAutoProxyConfiguration中importBeanDefinitionRegistrars 配置有AutoProxyRegistrar,所以會調用AutoProxyRegistrar#registerBeanDefinitions.代碼以下:
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) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound) {
String name = getClass().getSimpleName();
// log
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
得到importingClassMetadata中的註解類型
依次遍歷,若是遍歷到@EnableTransactionManagement 註解
若是@EnableTransactionManagement 配置的mode 爲PROXY,則註冊類型爲InfrastructureAdvisorAutoProxyCreator,id爲org.springframework.aop.config.internalAutoProxyCreator的bean
若是@EnableTransactionManagement 配置的proxyTargetClass爲true,則向beanFactory中id爲org.springframework.aop.config.internalAutoProxyCreator的bean添加proxyTargetClass的屬性,值爲true
若是最終沒有找到@EnableTransactionManagement,則打印日誌
EnableTransactionManagementConfiguration 是被TransactionAutoConfiguration 導入.所以會調用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法進行註冊
TransactionTemplateConfiguration 是被TransactionTemplateConfiguration導入的, 所以會調用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法進行註冊.同時因爲聲明瞭一個被@bean註解的方法,所以會調用loadBeanDefinitionsForBeanMethod進行註冊
TransactionAutoConfiguration 是被啓動類導入,所以會調用ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass方法進行註冊.
同時因爲有一個被@bean註解的方法,所以會調用loadBeanDefinitionsForBeanMethod進行註冊
最後,因爲經過@EnableConfigurationProperties間接導入了2個BeanDefinitionsFromRegistrar.依次會依次調用其registerBeanDefinitions方法.
ConfigurationPropertiesBeanRegistrar–> 會向BeanDefinitionRegistry註冊一個id爲spring.transaction-org.springframework.boot.autoconfigure.transaction.TransactionProperties,類型爲TransactionProperties的bean
ConfigurationPropertiesBindingPostProcessorRegistrar–>
若是BeanDefinitionRegistry中不存id爲org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor的bean,則:
註冊id爲org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor,類型爲ConfigurationBeanFactoryMetaData的bean
註冊id爲org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store,類型爲ConfigurationBeanFactoryMetaData的bean
注意:關於解析配置類的流程在spring boot 源碼解析11-ConfigurationClassPostProcessor類加載解析中詳細解析
解析流程圖以下:
加載流程就比較簡單了,這裏就不畫了--------------------- 版權聲明:本文爲CSDN博主「一個努力的碼農」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/qq_26000415/article/details/79021958