spring5 源碼深度解析----- Spring事務 是怎么通過AOP實現的?(100%理解Spring事務)

此篇文章需要有SpringAOP基礎,知道AOP底層原理可以更好的理解Spring的事務處理。

自定義標簽

對于Spring中事務功能的代碼分析,我們首先從配置文件開始人手,在配置文件中有這樣一個配置:<tx:annotation-driven/>。可以說此處配置是事務的開關,如果沒有此處配置,那么Spring中將不存在事務的功能。那么我們就從這個配置開始分析。

根據之前的分析,我們因此可以判斷,在自定義標簽中的解析過程中一定是做了一些輔助操作,于是我們先從自定義標簽入手進行分析。使用Idea搜索全局代碼,關鍵字annotation-driven,最終鎖定類TxNamespaceHandler,在TxNamespaceHandler中的 init 方法中:

@Override
public void init() {
    registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
    registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
    registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

在遇到諸如tx:annotation-driven為開頭的配置后,Spring都會使用AnnotationDrivenBeanDefinitionParser類的parse方法進行解析。

@Override
@Nullable
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的方式進行事務切入(Spring中的事務是以AOP為基礎的),那么可以使用這樣的配置:

<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>

注冊 InfrastructureAdvisorAutoProxyCreator

我們以默認配置為例進行分析,進人AopAutoProxyConfigurer類的configureAutoProxyCreator:

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
    //向IOC注冊InfrastructureAdvisorAutoProxyCreator這個類型的Bean
    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.
        // 創建AnnotationTransactionAttributeSource類型的Bean
        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.
        // 創建TransactionInterceptor類型的Bean
        RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
        interceptorDef.setSource(eleSource);
        interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        registerTransactionManager(element, interceptorDef);
        interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

        // Create the TransactionAttributeSourceAdvisor definition.
        // 創建BeanFactoryTransactionAttributeSourceAdvisor類型的Bean
        RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
        advisorDef.setSource(eleSource);
        advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 將上面AnnotationTransactionAttributeSource類型Bean注入進上面的Advisor
        advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        // 將上面TransactionInterceptor類型Bean注入進上面的Advisor
        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
        if (element.hasAttribute("order")) {
            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
        }
        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);
        // 將上面三個Bean注冊進IOC中
        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);
    }
}

這里分別是注冊了三個Bean,和一個InfrastructureAdvisorAutoProxyCreator,其中三個Bean支撐了整個事務的功能。

我們首先需要回顧一下AOP的原理,AOP中有一個 Advisor 存放在代理類中,而Advisor中有advise與pointcut信息,每次執行被代理類的方法時都會執行代理類的invoke(如果是JDK代理)方法,而invoke方法會根據advisor中的pointcut動態匹配這個方法需要執行的advise鏈,遍歷執行advise鏈,從而達到AOP切面編程的目的。

  • BeanFactoryTransactionAttributeSourceAdvisor:首先看這個類的繼承結構,可以看到這個類其實是一個Advisor,其實由名字也能看出來,類中有幾個關鍵地方注意一下,在之前的注冊過程中,將兩個屬性注入進這個Bean中:
// 將上面AnnotationTransactionAttributeSource類型Bean注入進上面的Advisor
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
// 將上面TransactionInterceptor類型Bean注入進上面的Advisor
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);

那么它們被注入成什么了呢?進入BeanFactoryTransactionAttributeSourceAdvisor一看便知。

@Nullable
private TransactionAttributeSource transactionAttributeSource;

在其父類中有屬性:

@Nullable
private String adviceBeanName;

也就是說,這里先將上面的TransactionInterceptor的BeanName傳入到Advisor中,然后將AnnotationTransactionAttributeSource這個Bean注入到Advisor中,那么這個Source Bean有什么用呢?可以繼續看看BeanFactoryTransactionAttributeSourceAdvisor的源碼。

private final TransactionAttributeSourcePointcut pointcut = new     TransactionAttributeSourcePointcut() {
    @Override
    @Nullable
    protected TransactionAttributeSource getTransactionAttributeSource() {
        return transactionAttributeSource;
    }
};

看到這里應該明白了,這里的Source是提供了pointcut信息,作為存放事務屬性的一個類注入進Advisor中,到這里應該知道注冊這三個Bean的作用了吧?首先注冊pointcut、advice、advisor,然后將pointcut和advice注入進advisor中,在之后動態代理的時候會使用這個Advisor去尋找每個Bean是否需要動態代理(取決于是否有開啟事務),因為Advisor有pointcut信息。

  • InfrastructureAdvisorAutoProxyCreator:在方法開頭,首先就調用了AopNamespeceUtils去注冊了這個Bean,那么這個Bean是干什么用的呢?還是先看看這個類的結構。這個類繼承了AbstractAutoProxyCreator,看到這個名字,熟悉AOP的話應該已經知道它是怎么做的了吧?其次這個類還實現了BeanPostProcessor接口,凡事實現了這個BeanPost接口的類,我們首先關注的就是它的postProcessAfterInitialization方法,這里在其父類也就是剛剛提到的AbstractAutoProxyCreator這里去實現。(這里需要知道Spring容器初始化Bean的過程,關于BeanPostProcessor的使用我會另開一篇講解。如果不知道只需了解如果一個Bean實現了BeanPostProcessor接口,當所有Bean實例化且依賴注入之后初始化方法之后會執行這個實現Bean的postProcessAfterInitialization方法)

進入這個函數:

public static void registerAutoProxyCreatorIfNecessary(
        ParserContext parserContext, Element sourceElement) {

    BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
            parserContext.getRegistry(), parserContext.extractSource(sourceElement));
    useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
    registerComponentIfNecessary(beanDefinition, parserContext);
}

@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
        @Nullable Object source) {

    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

對于解析來的代碼流程AOP中已經有所分析,上面的兩個函數主要目的是注冊了InfrastructureAdvisorAutoProxyCreator類型的bean,那么注冊這個類的目的是什么呢?查看這個類的層次,如下圖所示:

 

從上面的層次結構中可以看到,InfrastructureAdvisorAutoProxyCreator間接實現了SmartInstantiationAwareBeanPostProcessor,而SmartInstantiationAwareBeanPostProcessor又繼承自InstantiationAwareBeanPostProcessor,也就是說在Spring中,所有bean實例化時Spring都會保證調用其postProcessAfterInstantiation方法,其實現是在父類AbstractAutoProxyCreator類中實現。

以之前的示例為例,當實例化AccountServiceImpl的bean時便會調用此方法,方法如下:

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        // 根據給定的bean的class和name構建出key,格式:beanClassName_beanName
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (!this.earlyProxyReferences.contains(cacheKey)) {
            // 如果它適合被代理,則需要封裝指定bean
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

 這里實現的主要目的是對指定bean進行封裝,當然首先要確定是否需要封裝,檢測與封裝的工作都委托給了wrapIfNecessary函數進行。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    // 如果處理過這個bean的話直接返回
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 之后如果Bean匹配不成功,會將Bean的cacheKey放入advisedBeans中
    // value為false,所以這里可以用cacheKey判斷此bean是否之前已經代理不成功了
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 這里會將Advise、Pointcut、Advisor類型的類過濾,直接不進行代理,return
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
           // 這里即為不成功的情況,將false放入Map中
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 這里是主要驗證的地方,傳入Bean的class與beanName去判斷此Bean有哪些Advisor
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 如果有相應的advisor被找到,則用advisor與此bean做一個動態代理,將這兩個的信息
    // 放入代理類中進行代理
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 創建代理的地方
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        // 返回代理對象
        return proxy;
    }
    // 如果此Bean沒有一個Advisor匹配,將返回null也就是DO_NOT_PROXY
    // 也就是會走到這一步,將其cacheKey,false存入Map中
    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    // 不代理直接返回原bean
    return bean;
}

wrapIfNecessary函數功能實現起來很復雜,但是邏輯上理解起來還是相對簡單的,在wrapIfNecessary函數中主要的工作如下:

(1)找出指定bean對應的增強器。

(2)根據找出的增強器創建代理。

聽起來似乎簡單的邏輯,Spring中又做了哪些復雜的工作呢?對于創建代理的部分,通過之前的分析相信大家已經很熟悉了,但是對于增強器的獲取,Spring又是怎么做的呢?

獲取對應class/method的增強器

獲取指定bean對應的增強器,其中包含兩個關鍵字:增強器與對應。也就是說在 getAdvicesAndAdvisorsForBean函數中,不但要找出增強器,而且還需要判斷增強器是否滿足要求。

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
        Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

尋找候選增強器

protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
}

public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // 獲取BeanFactory中所有對應Advisor.class的類名
        // 這里和AspectJ的方式有點不同,AspectJ是獲取所有的Object.class,然后通過反射過濾有注解AspectJ的類
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    List<Advisor> advisors = new ArrayList<>();
    for (String name : advisorNames) {
        if (isEligibleBean(name)) {
            if (this.beanFactory.isCurrentlyInCreation(name)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping currently created advisor '" + name + "'");
                }
            }
            else {
                try {
                    //直接獲取advisorNames的實例,封裝進advisors數組
                    advisors.add(this.beanFactory.getBean(name, Advisor.class));
                }
                catch (BeanCreationException ex) {
                    Throwable rootCause = ex.getMostSpecificCause();
                    if (rootCause instanceof BeanCurrentlyInCreationException) {
                        BeanCreationException bce = (BeanCreationException) rootCause;
                        String bceBeanName = bce.getBeanName();
                        if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Skipping advisor '" + name +
                                        "' with dependency on currently created bean: " + ex.getMessage());
                            }
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}

首先是通過BeanFactoryUtils類提供的工具方法獲取所有對應Advisor.class的類,獲取辦法無非是使用ListableBeanFactory中提供的方法:

String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);

在我們講解自定義標簽時曾經注冊了一個類型為 BeanFactoryTransactionAttributeSourceAdvisor 的 bean,而在此 bean 中我們又注入了另外兩個Bean,那么此時這個 Bean 就會被開始使用了。因為 BeanFactoryTransactionAttributeSourceAdvisor同樣也實現了 Advisor接口,那么在獲取所有增強器時自然也會將此bean提取出來, 并隨著其他增強器一起在后續的步驟中被織入代理。

候選增強器中尋找到匹配項

當找出對應的增強器后,接下來的任務就是看這些增強器是否與對應的class匹配了,當然不只是class,class內部的方法如果匹配也可以通過驗證。

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
    if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
    }
    List<Advisor> eligibleAdvisors = new ArrayList<>();
    // 首先處理引介增強
    for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    for (Advisor candidate : candidateAdvisors) {
        // 引介增強已經處理
        if (candidate instanceof IntroductionAdvisor) {
            // already processed
            continue;
        }
        // 對于普通bean的處理
        if (canApply(candidate, clazz, hasIntroductions)) {
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    else {
        // It doesn't have a pointcut so we assume it applies.
        return true;
    }
}

BeanFactoryTransactionAttributeSourceAdvisor 間接實現了PointcutAdvisor。 因此,在canApply函數中的第二個if判斷時就會通過判斷,會將BeanFactoryTransactionAttributeSourceAdvisor中的getPointcut()方法返回值作為參數繼續調用canApply方法,而 getPoint()方法返回的是TransactionAttributeSourcePointcut類型的實例。對于 transactionAttributeSource這個屬性大家還有印象嗎?這是在解析自定義標簽時注入進去的。

private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
    @Override
    @Nullable
    protected TransactionAttributeSource getTransactionAttributeSource() {
        return transactionAttributeSource;
    }
};

那么,使用TransactionAttributeSourcePointcut類型的實例作為函數參數繼續跟蹤canApply。

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
    Assert.notNull(pc, "Pointcut must not be null");
    if (!pc.getClassFilter().matches(targetClass)) {
        return false;
    }

    // 此時的pc表示TransactionAttributeSourcePointcut
    // pc.getMethodMatcher()返回的正是自身(this)
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }

    IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
    if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
    }

    Set<Class<?>> classes = new LinkedHashSet<>();
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    //獲取對應類的所有接口
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    //對類進行遍歷
    for (Class<?> clazz : classes) {
        //反射獲取類中所有的方法
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        for (Method method : methods) {
            //對類和方法進行增強器匹配
            if (introductionAwareMethodMatcher != null ?
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                    methodMatcher.matches(method, targetClass)) {
                return true;
            }
        }
    }

    return false;
}

通過上面函數大致可以理清大體脈絡,首先獲取對應類的所有接口并連同類本身一起遍歷,遍歷過程中又對類中的方法再次遍歷,一旦匹配成功便認為這個類適用于當前增強器。

到這里我們不禁會有疑問,對于事物的配置不僅僅局限于在函數上配置,我們都知道,在類或接口上的配置可以延續到類中的每個函數,那么,如果針對每個函數迸行檢測,在類本身上配罝的事務屬性豈不是檢測不到了嗎?帶著這個疑問,我們繼續探求matcher方法。

做匹配的時候 methodMatcher.matches(method, targetClass)會使用 TransactionAttributeSourcePointcut 類的 matches 方法。

@Override
public boolean matches(Method method, Class<?> targetClass) {
    if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
        return false;
    }
    // 自定義標簽解析時注入
    TransactionAttributeSource tas = getTransactionAttributeSource();
    return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

此時的 tas 表示 AnnotationTransactionAttributeSource 類型,這里會判斷tas.getTransactionAttribute(method, targetClass) != null,而 AnnotationTransactionAttributeSource 類型的 getTransactionAttribute 方法如下:

@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (method.getDeclaringClass() == Object.class) {
        return null;
    }

    Object cacheKey = getCacheKey(method, targetClass);
    Object cached = this.attributeCache.get(cacheKey);
    //先從緩存中獲取TransactionAttribute
    if (cached != null) {
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            return null;
        }
        else {
            return (TransactionAttribute) cached;
        }
    }
    else {
        // 如果緩存中沒有,工作又委托給了computeTransactionAttribute函數
        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.isDebugEnabled()) {
                logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
            }
            //加入緩存中
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

嘗試從緩存加載,如果對應信息沒有被緩存的話,工作又委托給了computeTransactionAttribute函數,在computeTransactionAttribute函數中我們終于看到了事務標簽的提取過程。

提取事務標簽

@Nullable
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代表實現類中的方法
    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;
}

對于事務屬性的獲取規則相信大家都已經很清楚,如果方法中存在事務屬性,則使用方法上的屬性,否則使用方法所在的類上的屬性,如果方法所在類的屬性上還是沒有搜尋到對應的事務屬性,那么在搜尋接口中的方法,再沒有的話,最后嘗試搜尋接口的類上面的聲明。對于函數computeTransactionAttribute中的邏輯與我們所認識的規則并無差別,但是上面函數中并沒有真正的去做搜尋事務屬性的邏輯,而是搭建了個執行框架,將搜尋事務屬性的任務委托給了 findTransactionAttribute 方法去執行。

@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
    return determineTransactionAttribute(clazz);
}

@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
    for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
        TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
        if (attr != null) {
            return attr;
        }
    }
    return null;
}

this.annotationParsers 是在當前類 AnnotationTransactionAttributeSource 初始化的時候初始化的,其中的值被加入了 SpringTransactionAnnotationParser,也就是當進行屬性獲取的時候其實是使用 SpringTransactionAnnotationParser 類的 parseTransactionAnnotation 方法進行解析的。

@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
            ae, Transactional.class, false, false);
    if (attributes != null) {
        return parseTransactionAnnotation(attributes);
    }
    else {
        return null;
    }
}

至此,我們終于看到了想看到的獲取注解標記的代碼。首先會判斷當前的類是否含有 Transactional注解,這是事務屬性的基礎,當然如果有的話會繼續調用parseTransactionAnnotation 方法解析詳細的屬性。

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
    RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    Propagation propagation = attributes.getEnum("propagation");
    // 解析propagation
    rbta.setPropagationBehavior(propagation.value());
    Isolation isolation = attributes.getEnum("isolation");
    // 解析isolation
    rbta.setIsolationLevel(isolation.value());
    // 解析timeout
    rbta.setTimeout(attributes.getNumber("timeout").intValue());
    // 解析readOnly
    rbta.setReadOnly(attributes.getBoolean("readOnly"));
    // 解析value
    rbta.setQualifier(attributes.getString("value"));
    ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
    // 解析rollbackFor
    Class<?>[] rbf = attributes.getClassArray("rollbackFor");
    for (Class<?> rbRule : rbf) {
        RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    // 解析rollbackForClassName
    String[] rbfc = attributes.getStringArray("rollbackForClassName");
    for (String rbRule : rbfc) {
        RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    // 解析noRollbackFor
    Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
    for (Class<?> rbRule : nrbf) {
        NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    // 解析noRollbackForClassName
    String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
    for (String rbRule : nrbfc) {
        NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    rbta.getRollbackRules().addAll(rollBackRules);
    return rbta;
}

至此,我們終于完成了事務標簽的解析。回顧一下,我們現在的任務是找出某個增強器是否適合于對應的類,而是否匹配的關鍵則在于是否從指定的類或類中的方法中找到對應的事務屬性,現在,我們以AccountServiceImpl為例,已經在它的接口AccountServiceImp中找到了事務屬性,所以,它是與事務增強器匹配的,也就是它會被事務功能修飾。

至此,事務功能的初始化工作便結束了,當判斷某個bean適用于事務增強時,也就是適用于增強器BeanFactoryTransactionAttributeSourceAdvisor

BeanFactoryTransactionAttributeSourceAdvisor 作為 Advisor 的實現類,自然要遵從 Advisor 的處理方式,當代理被調用時會調用這個類的增強方法,也就是此bean的Advice,又因為在解析事務定義標簽時我們把Transactionlnterceptor類的bean注人到了 BeanFactoryTransactionAttributeSourceAdvisor中,所以,在調用事務增強器增強的代理類時會首先執行Transactionlnterceptor進行增強,同時,也就是在Transactionlnterceptor類中的invoke方法中完成了整個事務的邏輯。

 

posted @ 2019-10-14 11:07 chen_hao 閱讀(...) 評論(...) 編輯 收藏
ag二分彩