Spring事務(二)事務自定義標簽


摘要: 本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。

 

目錄

一、注冊 InfrastructureAdvisorAutoProxyCreator

二、獲取對應class/method的增強器

1. 尋找候選增強器

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

3. 提取事務標簽

 

對於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方法進行解析。

/**
 * Parses the {@code <tx:annotation-driven/>} tag. Will
 * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
 * with the container as necessary.
 */
@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) {
    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.
        //創建TransactionAttributeSource的bean
        RootBeanDefinition sourceDef = new RootBeanDefinition(
                "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
        sourceDef.setSource(eleSource);
        sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 注冊bean,並使用Spring中的定義規則生成beanName
        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));
        // 注冊bean,並使用Spring中的定義規則生成beanName
        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

        // Create the TransactionAttributeSourceAdvisor definition.
        // 創建TransactionAttributeSourceAdvisor的bean
        RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
        advisorDef.setSource(eleSource);
        advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
        // 將interceptorName的bean注入advisorDef的adviceBeanName屬性中
        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
        // 如果配置了order屬性,則加入到bean中
        if (element.hasAttribute("order")) {
            advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
        }
        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

        // 創建CompositeComponentDefinition
        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,很多讀者會直接略過,認為只是注冊三個bean而已,確實,這里只注冊了三個bean,但是這三個bean支撐了整個的事務功能,那么這三個bean是怎么組織起來的呢?

首先,其中的兩個bean被注冊到了一個名為advisorDef的bean中,advisorDef使用BeanFactoryTransactionAttributeSourceAdvisor作為其class屬性。也就是說BeanFactoryTransactionAttributeSourceAdvisor代表着當前bean,如下圖所示,具體代碼如下:

advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);

那么如此組裝的目的是什么呢?我們暫且留下一個懸念,接着分析代碼。上面函數configureAutoProxyCreator中的第一句貌似很簡單卻是很重要的代碼:

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

進入這個函數:

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類中實現。

以之前的示例為例,當實例化userService的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) {
    // 如果已經處理過
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    // 無需增強
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }
    // 給定的bean類是否代表一個基礎設施類,基礎設施類不應代理,或者配置了指定bean不需要自動代理
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 如果存在增強方法則創建代理
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    // 如果獲取到了增強則需要針對增強創建代理
    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;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    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();
}

/**
 * Find all eligible Advisors for auto-proxying this class.
 * @param beanClass the clazz to find advisors for
 * @param beanName the name of the currently proxied bean
 * @return the empty List, not {@code null},
 * if there are no pointcuts or interceptors
 * @see #findCandidateAdvisors
 * @see #sortAdvisors
 * @see #extendAdvisors
 */
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;
}

其實我們也漸漸地體會到了Spring中代碼的優秀,即使是一個很復雜的邏輯,在Spring中也會被拆分成若干個小的邏輯,然后在每個函數中實現,使得每個函數的邏輯簡單到我們能快速地理解,而不會像有些人開發的那樣,將一大堆的邏輯都羅列在一個函數中,給后期維護人員造成巨大的困擾。

同樣,通過上面的函數,Spring又將任務進行了拆分,分成了獲取所有增強器與增強器是否匹配兩個功能點。

1. 尋找候選增強器

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) {
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the auto-proxy creator apply to them!
        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 {
                    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());
                            }
                            // Ignore: indicates a reference back to the bean we're trying to advise.
                            // We want to find advisors other than the currently created bean itself.
                            continue;
                        }
                    }
                    throw ex;
                }
            }
        }
    }
    return advisors;
}

對於上面的函數,你看懂其中的奧妙了嗎?首先是通過BeanFactoryUtils類提供的工具方法獲取所有對應Advisor.class的類,獲取辦法無非是使用ListableBeanFactory中提供的方法:

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

而當我們知道增強器在容器中的beanName時,獲取增強器已經不是問題了,在BeanFactory 中提供了這樣的方法,可以幫助我們快速定位對應的bean實例。

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

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

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

當找出對應的增強器后,接下來的任務就是看這些增強器是否與對應的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;
    }
}

當前我們分析的是對於UserService是否適用於此增強方法,那么當前的advisor就是之前查找出來的類型為BeanFactoryTransactionAttributeSourceAdvisor的bean實例,而通過類的層次結構我們又知道: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 類型,而 AnnotationTransactionAttributeSource 類型的 getTransactionAttribute 方法如下:

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

    // First, see if we have a cached value.
    Object cacheKey = getCacheKey(method, targetClass);
    Object 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 (TransactionAttribute) cached;
        }
    }
    else {
        // We need to work it out.
        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;
    }
}

很遺憾,在getTransactionAttribute函數中並沒有找到我們想要的代碼,這里是指常規的一貫的套路。嘗試從緩存加載,如果對應信息沒有被緩存的話,工作又委托給了computeTransactionAttribute函數,在computeTransactionAttribute函數中我們終於看到了事務標簽的提取過程。

3. 提取事務標簽

@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);
}

/**
 * Determine the transaction attribute for the given method or class.
 * <p>This implementation delegates to configured
 * {@link TransactionAnnotationParser TransactionAnnotationParsers}
 * for parsing known annotations into Spring's metadata attribute class.
 * Returns {@code null} if it's not transactional.
 * <p>Can be overridden to support custom annotations that carry transaction metadata.
 * @param ae the annotated method or class
 * @return the configured transaction attribute,
 * or {@code null} if none was found
 */
@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;
}

上面方法中實現了對對應類或者方法的事務屬性解析,你會在這個類中看到任何你常用或者不常用的屬性提取。

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

至此,事務功能的初始化工作便結束了,當判斷某個bean適用於事務增強時,也就是適用於增強器BeanFactoryTransactionAttributeSourceAdvisor,沒錯,還是這個類,所以說,在自定義標簽解析時,注入的類成為了整個事務功能的基礎。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM