1 概述
2 Spring Boot配置入口
3 BeanFactoryTransactionAttributeSourceAdvisor事務(wù)AOP實(shí)現(xiàn)
1 概述
首先要先了解,Spring在通過@Transactional注解創(chuàng)建事務(wù)也是通過AOP實(shí)現(xiàn)的,具體的AOP創(chuàng)建入口,可以閱讀筆者文章Spring Boot源碼-Spring AOP創(chuàng)建代理的入口(但是在該文章只介紹了AOP的入口,沒有介紹其具體實(shí)現(xiàn))。通過該文章我們可以知道,Spring是通過BeanPostProcessor.postProcessAfterInitialization創(chuàng)建動(dòng)態(tài)代理實(shí)現(xiàn)切面的。AnnotationAwareAspectJAutoProxyCreator是檢測(cè)是否需要?jiǎng)?chuàng)建AOP織入的關(guān)鍵類。在實(shí)例化一個(gè)Bean時(shí),其通過在容器中查找是否有能夠使用在該bean相關(guān)方法上的Advisor來實(shí)現(xiàn)織入。
好了,理解了上面AOP的大概創(chuàng)建過程,后面再看注解@Transactional的實(shí)現(xiàn)就比較簡(jiǎn)單了。
2 Spring Boot配置入口
Spring Boot自動(dòng)配置如何實(shí)現(xiàn)的就不再具體介紹了,首先我們可以在spring.factories文件中看到事務(wù)自動(dòng)配置相關(guān)類TransactionAutoConfiguration,但是我們看其源碼可以知道其類上有一個(gè)注解@ConditionalOnClass(PlatformTransactionManager.class),也就是說TransactionAutoConfiguration依賴PlatformTransactionManager,所以在啟用事務(wù)時(shí)必須引入數(shù)據(jù)庫相關(guān)的jar包。
下面我們看TransactionAutoConfiguration的嵌套內(nèi)部類EnableTransactionManagementConfiguration,Spring在處理@Configuration注解的配置類時(shí)也會(huì)同步處理其所有內(nèi)部類,通過源碼可知EnableTransactionManagementConfiguration的生效要求存在PlatformTransactionManager.class類型的bean,PlatformTransactionManager.class類型的bean是在何時(shí)加入到容器中的呢?我們可以通過在TransactionAutoConfiguration源碼上找到答案,TransactionAutoConfiguration類定義處有如下注解:
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
我們這里看下DataSourceTransactionManagerAutoConfiguration.class,通過搜索可以知道DataSourceTransactionManagerAutoConfiguration也在spring.factories文件中,所以也會(huì)被注冊(cè)到容器中,DataSourceTransactionManagerAutoConfiguration源碼比較簡(jiǎn)單,就是向容器中注冊(cè)了DataSourceTransactionManager,DataSourceTransactionManagerAutoConfiguration依賴的DateSource是通過spring.factories文件中的DataSourceAutoConfiguration注冊(cè)到容器中的。
現(xiàn)在我們?cè)倩貋砜?code>TransactionAutoConfiguration的嵌套內(nèi)部類EnableTransactionManagementConfiguration,EnableTransactionManagementConfiguration的兩個(gè)內(nèi)部類JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration都使用類注解EnableTransactionManagement,而注解EnableTransactionManagement則使用了@Import(TransactionManagementConfigurationSelector.class),@Import注解的原理這里不具體介紹,這也是Spring Boot自動(dòng)配置的關(guān)鍵。TransactionManagementConfigurationSelector則通過selectImports方法引入了配置AutoProxyRegistrar和ProxyTransactionManagementConfiguration,AutoProxyRegistrar主要是保證如果容器中沒有相關(guān)AOP增強(qiáng)類存在時(shí),引入一個(gè)AOP增強(qiáng)類,為后面使用AOP實(shí)現(xiàn)事務(wù)作準(zhǔn)備。ProxyTransactionManagementConfiguration就像容器注冊(cè)了事務(wù)的關(guān)鍵實(shí)現(xiàn)類BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource以及TransactionInterceptor。
3 BeanFactoryTransactionAttributeSourceAdvisor事務(wù)AOP實(shí)現(xiàn)
BeanFactoryTransactionAttributeSourceAdvisor就是查看方法是否存在@Transactional注解并決定是否創(chuàng)建事務(wù)的實(shí)現(xiàn)所在。BeanFactoryTransactionAttributeSourceAdvisor.pointcut實(shí)現(xiàn)如下:
//BeanFactoryTransactionAttributeSourceAdvisor
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
//這里使用的是匿名內(nèi)部類,所以返回的
//transactionAttributeSource是
//BeanFactoryTransactionAttributeSourceAdvisor
//的域AnnotationTransactionAttributeSource
return transactionAttributeSource;
}
};
好了,在決定相關(guān)bean要不要采用事務(wù)控制時(shí),我們看下上面源碼中匿名類的父類TransactionAttributeSourcePointcut.matches方法實(shí)現(xiàn):
//TransactionAttributeSourcePointcut
@Override
public boolean matches(Method method, Class<?> targetClass) {
//首先過濾一些框架內(nèi)部使用的類
if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
return false;
}
//這個(gè)上面介紹過,返回的是
//BeanFactoryTransactionAttributeSourceAdvisor
//的域AnnotationTransactionAttributeSource
TransactionAttributeSource tas = getTransactionAttributeSource();
//因?yàn)閠as為AnnotationTransactionAttributeSource,所以這里
//通過tas.getTransactionAttribute查看該方法是否有事務(wù)相關(guān)注解
//如果有的話,就需要通過AOP進(jìn)行事務(wù)處理
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
下面我們看AnnotationTransactionAttributeSourcegetTransactionAttribute實(shí)現(xiàn),該方法在AnnotationTransactionAttributeSource父類AbstractFallbackTransactionAttributeSource實(shí)現(xiàn)如下:
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
//首先查看緩存是否存在,避免重復(fù)解析事務(wù)元數(shù)據(jù)
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.
//嘗試從方法中獲取事務(wù)相關(guān)配置元數(shù)據(jù)
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
//解析完之后放到緩存里
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
//根據(jù)不同的TransactionAttributeSource實(shí)現(xiàn)從不同的配置
//中讀取元數(shù)據(jù),這里因?yàn)椴捎米⒔?,所有從注解中讀取事務(wù)配置
//子類則通過重寫findTransactionAttribute(Class<?> clazz)
//以及findTransactionAttribute(Method method)方法提供從不同的
//配置方式中讀取事務(wù)
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;
}
下面我們看AnnotationTransactionAttributeSource.findTransactionAttribute(Class<?> clazz)以及AnnotationTransactionAttributeSource.findTransactionAttribute(Method method)方法實(shí)現(xiàn),其實(shí)這兩個(gè)方法都調(diào)用了determineTransactionAttribute(AnnotatedElement element)方法:
//AnnotationTransactionAttributeSource
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
//determineTransactionAttribute則通過注冊(cè)的一系列
//TransactionAnnotationParser從類或者方法注解中解析
//事務(wù)配置
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
//在AnnotationTransactionAttributeSource構(gòu)造函數(shù)中,
//根據(jù)檢測(cè)環(huán)境中的是否存在相關(guān)jpa實(shí)現(xiàn)的類,注冊(cè)了相關(guān)的
//TransactionAnnotationParser
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
if (jta12Present || ejb3Present) {
this.annotationParsers = new LinkedHashSet<>(4);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
else {
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
下面我們看默認(rèn)的SpringTransactionAnnotationParser是如何完成事務(wù)配置解析的:
//SpringTransactionAnnotationParser
//到這里終于看到了熟悉的Transactional注解,下面過程就不再介紹了,
//主要就是讀取Transactional注解中的關(guān)于事務(wù)的配置
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}