Spring Boot源碼-Transactional注解實(shí)現(xiàn)事務(wù)AOP原理


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)部類JdkDynamicAutoProxyConfigurationCglibAutoProxyConfiguration都使用類注解EnableTransactionManagement,而注解EnableTransactionManagement則使用了@Import(TransactionManagementConfigurationSelector.class)@Import注解的原理這里不具體介紹,這也是Spring Boot自動(dòng)配置的關(guān)鍵。TransactionManagementConfigurationSelector則通過selectImports方法引入了配置AutoProxyRegistrarProxyTransactionManagementConfiguration,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;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容