spring事物(一),@EnableTransactionManagement @Transactional 啟動解析


原文連接:https://www.cnblogs.com/leaveast/p/11765503.html,侵刪

1.事物的聲明階段

  @EnableTransactionManagement,是我們開啟注解事物的第一步,我們來看下這個類為我們干了什么

復制代碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
</span><span style="color: #0000ff;">boolean</span> proxyTargetClass() <span style="color: #0000ff;">default</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">;

AdviceMode mode() </span><span style="color: #0000ff;">default</span><span style="color: #000000;"> AdviceMode.PROXY;

</span><span style="color: #0000ff;">int</span> order() <span style="color: #0000ff;">default</span><span style="color: #000000;"> Ordered.LOWEST_PRECEDENCE;  

}

復制代碼

  我們主要看 TransactionManagementConfigurationSelector 干了件什么事情。它主要往spring 容器中導入了 AutoProxyRegistrar , ProxyTransactionManagementConfiguration兩個對象。

 

 

復制代碼
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    @Override
    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;
        }
    }

}

復制代碼

 

ProxyTransactionManagementConfiguration的作用,我們可以看到此類是一個配置類,主要為spring容器中導入了3個bean。這三個bean分別的作用,我們下來詳說

復制代碼
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name </span>=<span style="color: #000000;"> TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    BeanFactoryTransactionAttributeSourceAdvisor advisor </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    advisor.setAdvice(transactionInterceptor());
    advisor.setOrder(</span><span style="color: #0000ff;">this</span>.enableTx.&lt;Integer&gt;getNumber("order"<span style="color: #000000;">));
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> advisor;
}

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> TransactionAttributeSource transactionAttributeSource() {
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> AnnotationTransactionAttributeSource();
}

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> TransactionInterceptor transactionInterceptor() {
    TransactionInterceptor interceptor </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource());
    </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span>.txManager != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
        interceptor.setTransactionManager(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.txManager);
    }
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> interceptor;
}

}

復制代碼

AutoProxyRegistrar 這個類,實現了ImportBeanDefinitionRegistrar接口,主要是為容器中注入了 InfrastructureAdvisorAutoProxyCreator 這個bean。

復制代碼
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">final</span> Log logger =<span style="color: #000000;"> LogFactory.getLog(getClass());</span><span style="color: #000000;">
@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    </span><span style="color: #0000ff;">boolean</span> candidateFound = <span style="color: #0000ff;">false</span><span style="color: #000000;">;
    Set</span>&lt;String&gt; annoTypes =<span style="color: #000000;"> importingClassMetadata.getAnnotationTypes();
    </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (String annoType : annoTypes) {
        AnnotationAttributes candidate </span>=<span style="color: #000000;"> AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
        </span><span style="color: #0000ff;">if</span> (candidate == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
            </span><span style="color: #0000ff;">continue</span><span style="color: #000000;">;
        }
        Object mode </span>= candidate.get("mode"<span style="color: #000000;">);
        Object proxyTargetClass </span>= candidate.get("proxyTargetClass"<span style="color: #000000;">);
        </span><span style="color: #0000ff;">if</span> (mode != <span style="color: #0000ff;">null</span> &amp;&amp; proxyTargetClass != <span style="color: #0000ff;">null</span> &amp;&amp; AdviceMode.<span style="color: #0000ff;">class</span> == mode.getClass() &amp;&amp;<span style="color: #000000;">
                Boolean.</span><span style="color: #0000ff;">class</span> ==<span style="color: #000000;"> proxyTargetClass.getClass()) {
            candidateFound </span>= <span style="color: #0000ff;">true</span><span style="color: #000000;">;
            </span><span style="color: #0000ff;">if</span> (mode ==<span style="color: #000000;"> AdviceMode.PROXY) {
                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> ((Boolean) proxyTargetClass) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                    </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;
                }
            }
        }
    }</span><span style="color: #000000;">
}

  

  public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, null);
}

  public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}


}
復制代碼

我們首先來看一下這個類的繼承關系圖。

 

這個類首先是beanpostprocessor的實現類,他會對所有的bean做一次后置增強處理,我們在AbstractAutoProxyCreator中的 postProcessAfterInitialization 方法中可以看到,他會根據規則去對bean包裝從而創造滿足條件的代理。

復制代碼
/**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     * @see #getAdvicesAndAdvisorsForBean
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (!this.earlyProxyReferences.contains(cacheKey)) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
復制代碼

我們接下來進入 wrapIfNecessary 方法

復制代碼
    // 如果需要的話,包裝給定的bean,也就是說它是否有資格代理。
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create proxy if we have advice.</span>
    Object[] specificInterceptors = <span style="color: #ff0000;">getAdvicesAndAdvisorsForBean</span>(bean.getClass(), beanName, <span style="color: #0000ff;">null</span><span style="color: #000000;">);
    </span><span style="color: #0000ff;">if</span> (specificInterceptors !=<span style="color: #000000;"> DO_NOT_PROXY) {
        </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.advisedBeans.put(cacheKey, Boolean.TRUE);
        Object proxy </span>=<span style="color: #000000;"> createProxy(
                bean.getClass(), beanName, specificInterceptors, </span><span style="color: #0000ff;">new</span><span style="color: #000000;"> SingletonTargetSource(bean));
        </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.proxyTypes.put(cacheKey, proxy.getClass());
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> proxy;
    }

    </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.advisedBeans.put(cacheKey, Boolean.FALSE);
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> bean;
}</span></pre>
復制代碼

我們着重關注一下 getAdvicesAndAdvisorsForBean 方法

 

復制代碼
    @Override
    protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
        List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
        if (advisors.isEmpty()) {
            return DO_NOT_PROXY;
        }
        return advisors.toArray();
    }
復制代碼

 

這個方法沒什么說的,主要表達的意思是為bean找到合格的增強器。

復制代碼
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; }
復制代碼

在 findCandidateAdvisors 方法中,我們可以看到我們上文中注入的三個bean中的其中一個 BeanFactoryTransactionAttributeSourceAdvisor,這個bean可以理解為我們的事物增強器。

 

 

 

復制代碼
    public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = null;
        synchronized (this) {
            advisorNames = this.cachedAdvisorBeanNames;
            if (advisorNames == null) {
                // 找到上文注入的 BeanFactoryTransactionAttributeSourceAdvisor
                advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                        this.beanFactory, Advisor.class, true, false);
                this.cachedAdvisorBeanNames = advisorNames;
            }
        }
        if (advisorNames.length == 0) {
            return new LinkedList<Advisor>();
        }return advisors;
    }
復制代碼

 

接下來我們看 findAdvisorsThatCanApply 方法,這個方法主要實現了,候選的增強器是否可以對當前bean使用。

 

復制代碼
    public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
            return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        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;
            }
            if (canApply(candidate, clazz, hasIntroductions)) {
                eligibleAdvisors.add(candidate);
            }
        }
        return eligibleAdvisors;
    }
復制代碼

我們進入方法走到canApply處,繼續往下跟。

復制代碼
    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;
        }
    }
復制代碼

先判斷類型后做一次轉化,再次進入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;
        }
    MethodMatcher methodMatcher </span>=<span style="color: #000000;"> pc.getMethodMatcher();
    </span><span style="color: #0000ff;">if</span> (methodMatcher ==<span style="color: #000000;"> MethodMatcher.TRUE) {
        </span><span style="color: #008000;">//</span><span style="color: #008000;"> No need to iterate the methods if we're matching any method anyway...</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #000000;">;
    }

    IntroductionAwareMethodMatcher introductionAwareMethodMatcher </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
    </span><span style="color: #0000ff;">if</span> (methodMatcher <span style="color: #0000ff;">instanceof</span><span style="color: #000000;"> IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher </span>=<span style="color: #000000;"> (IntroductionAwareMethodMatcher) methodMatcher;
    }

    Set</span>&lt;Class&lt;?&gt;&gt; classes = <span style="color: #0000ff;">new</span> LinkedHashSet&lt;Class&lt;?&gt;&gt;<span style="color: #000000;">(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    classes.add(targetClass);
    </span><span style="color: #0000ff;">for</span> (Class&lt;?&gt;<span style="color: #000000;"> clazz : classes) {
        Method[] methods </span>=<span style="color: #000000;"> ReflectionUtils.getAllDeclaredMethods(clazz);
        </span><span style="color: #0000ff;">for</span><span style="color: #000000;"> (Method method : methods) {
            </span><span style="color: #0000ff;">if</span> ((introductionAwareMethodMatcher != <span style="color: #0000ff;">null</span> &amp;&amp;<span style="color: #000000;">
                    introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) </span>||<span style="color: #000000;"><span style="color: #ff0000;">
                    methodMatcher.matches(method, targetClass)</span>) {
                </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #000000;">;
            }
        }
    }

    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">;
}</span></pre>
復制代碼

進入matches方法,下來的代碼我會合並的連貫一些

復制代碼
@Override
    public boolean matches(Method method, Class<?> targetClass) {
        if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
            return false;
        }
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }
// 進入AbstractFallbackTransactionAttributeSource.getTransactionAttribute()
  TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
  TransactionAttribute txAttr = findTransactionAttribute(specificMethod);

 

復制代碼

進入解析的流程

復制代碼
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    <span style="color: #ff0000;">AnnotationAttributes attributes </span></span><span style="color: #ff0000;">= AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
    </span><span style="color: #0000ff;">if</span> (attributes != <span style="color: #0000ff;">null</span><span style="color: #000000;">) {
        </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> parseTransactionAnnotation(attributes);
    }
    </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> {
        </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
    }
}

</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> TransactionAttribute parseTransactionAnnotation(Transactional ann) {
    </span><span style="color: #0000ff;">return</span> parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, <span style="color: #0000ff;">false</span>, <span style="color: #0000ff;">false</span><span style="color: #000000;">));
}

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

}

復制代碼

此方法會先拿到標記為 Transcantional 注解的方法,然后遍歷屬性。最后返回attr,如果解析到的attr不為空,則會將此增強器對待增強的bean做增強處理。

 

復制代碼
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    </span><span style="color: #008000;">//</span><span style="color: #008000;"> Create proxy if we have advice.</span>
   <span style="color: #ff0000;"> 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;
    }

    </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.advisedBeans.put(cacheKey, Boolean.FALSE);
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> bean;
}</span></pre>
復制代碼

我們回到 wrapIfNecessary方法,如果返回的advisor不為空,我們會為他生成代理對象。 

Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

這里就跟我們的使用AOP創建代理無縫融合,在找到當前bean確定要進行增強處理和增強的advisor后,使用動態代理的方式創建代理對象。

 

 

 

 


免責聲明!

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



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