spring事物,@EnableTransactionManagement @Transactional 启动解析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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后,使用动态代理的方式创建代理对象。

 

 

 

 

以上是关于spring事物,@EnableTransactionManagement @Transactional 启动解析的主要内容,如果未能解决你的问题,请参考以下文章

spring详解——事物管理

Spring事物三千问Spring配置多数据源 vs 给多个数据源添加事物管理

spring全注解事务管理中怎么手动回滚事物

Spring的事物管理

spring事物源码分析篇三:业务代码的执行--事物增强器

spring事務