Spring 事务源码(3)—@EnableTransactionManagement事务注解源码解析

  基于最新Spring 5.x,详细介绍了Spring 事务源码,包括@EnableTransactionManagement事务注解源码解析

  上一篇文章:Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析中我们讲解了标签的解析源码,现在我们来看看用于替代该标签的注解@EnableTransactionManagement事务注解的源码解析。

Spring 事务源码 系列文章

Spring 5.x 源码汇总

Spring 事务源码(1)—<tx:advice/>事务标签源码解析

Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析

Spring 事务源码(3)—@EnableTransactionManagement事务注解源码解析

Spring 事务源码(4)—BeanFactoryTransactionAttributeSourceAdvisor注解事务通知器源码解析

Spring 事务源码(5)—TransactionInterceptor事务拦截器与事务的AOP增强实现

Spring 事务源码(6)—createTransactionIfNecessary处理事务属性并尝试创建事务【两万字】

Spring 事务源码(7)—事务的completeTransactionAfterThrowing回滚、commitTransactionAfterReturning提交以及事务源码总结【一万字】

文章目录

  • Spring 事务源码 系列文章
  • 1 @EnableTransactionManagement源码入口
  • 2 TransactionManagementConfigurationSelector
    • 2.1 AutoProxyRegistrar注册自动代理创建者
    • 2.2 ProxyTransactionManagementConfiguration注册事务管理bean
  • 3 小结

1 @EnableTransactionManagement源码入口

  @EnableTransactionManagement注解用于替代标签来开启声明式事务注解驱动!它是@Eenable开头的注解,这实际上就很简单了,我们在此前异步任务的源码:Spring @Async异步任务源码(1)—<task:annotation-driven/>、<task:executor/>、@EnableAsync解析的文章中@EnableAsync注解解析的部分就讲过,这样的注解的关键通常是内部的@Import元注解,@Import注解用于引入bean到容器中!

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//核心注解
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

    /**
     * 指示是否创建基于子类(CGLIB)的代理,而不是标准的基于Java接口的代理(false)。默认为false,即基于Java接口。
     * 仅当mode()设置为AdviceMode.PROXY时适用。
     */
    boolean proxyTargetClass() default false;

    /**
     * 指示应该如何应用事务性通知。
     * 

* 默认为AdviceMode.PROXY,即基于Spring AOP动态代理。请注意,代理模式只允许通过代理拦截调用。 * 同一个类中的本地方法互相调用中,被调用方法上的事务注解将被忽略,因为Spring的拦截器不会在这样的运行时场景中发挥作用。 * 对于更高级的拦截模式,考虑将其切换到AdviceMode.ASPECTJ,即以及Aspect的静态织入 */ AdviceMode mode() default AdviceMode.PROXY; /** * 指示在特定连接点应用多个通知时事务通知器的执行顺序。 *

* 默认为Ordered.LOWEST_PRECEDENCE */ int order() default Ordered.LOWEST_PRECEDENCE; }

2 TransactionManagementConfigurationSelector

  @Import注解引入的Class的类型不同,将会执行不同的解析流程,这一点我们在此前异步任务的源码中的@EnableAsync注解解析的部分也讲过了。@EnableTransactionManagement内部的@Import元注解指定的是TransactionManagementConfigurationSelector.class,这个类是一个ImportSelectorBean,因此我们直接看这个类的selectImports方法即可!
  TransactionManagementConfigurationSelector还继承了AdviceModeImportSelector,这是一个通用的基类,该基类及其实现类将会根据AdviceMode选择导入不同的注册的bean!这些特征说明TransactionManagementConfigurationSelector和@EnableAsync注解内部的@Import注解指定的AsyncConfigurationSelector.class属于同一体系。
  通常情况下,selectImports方法将会返回org.springframework.context.annotation.AutoProxyRegistrar和org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration这两个class,即将会注册这两个bean定义到容器中。

/**
 * 这是一个通用基类,用于根据AdviceMode来选择注册不同的bean定义,该基类被用于广泛的支持@Enable*注解
 * 比如@EnableAsync、@EnableCaching、@EnableTransactionManagement(需要spring-tx依赖)
 *
 * @param  注解类型泛型
 */
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {

    /**
     * AdviceMode属性的默认属性名字为"mode"
     */
    public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";


    /**
     * 获取AdviceMode属性的属性名,默认为"mode",子类可以覆盖重写
     */
    protected String getAdviceModeAttributeName() {
        return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME;
    }

    /**
     * 该方法就是核心方法,在解析@Import注解时就会自动调用
     * 

* 该方法首先会校验指定的注解中是否存在类型为AdviceMode名字为getAdviceModeAttributeName()返回值的属性 * 然后会调用另一个selectImports(AdviceMode adviceMode)方法,该方法被子类重写,用于根据mode值判断应该使用哪些bean */ @Override public final String[] selectImports(AnnotationMetadata importingClassMetadata) { //获取确定的泛型类型 Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class); Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector"); //获取该泛型注解的属性集合 AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (attributes == null) { throw new IllegalArgumentException(String.format( "@%s is not present on importing class '%s' as expected", annType.getSimpleName(), importingClassMetadata.getClassName())); } //从属性集合中根据AdviceMode属性的属性名获取属性值 AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName()); //调用selectImports(AdviceMode adviceMode)方法选择合适bean,该方法被子类重写 String[] imports = selectImports(adviceMode); //不能为null if (imports == null) { throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode); } return imports; } /** * 根据给定的AdviceMode确定应导入哪些类,该方法应被子类重写 *

* 返回null将会抛出IllegalArgumentException异常. */ @Nullable protected abstract String[] selectImports(AdviceMode adviceMode); } /** * 子类实现了AdviceModeImportSelector,泛型类型为@EnableTransactionManagement注解 * 重写了selectImports(AdviceMode adviceMode)方法 */ public class TransactionManagementConfigurationSelector extends org.springframework.context.annotation.AdviceModeImportSelector<org.springframework.transaction.annotation.EnableTransactionManagement> { /** * 如果EnableAsync#mode是PROXY,那么返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration * 如果EnableAsync#mode是ASPECTJ,那么返回AspectJ(Jta)TransactionManagementConfiguration */ @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: //一般都是PROXY,因此将会注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration的bean定义,进行动态代理 return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: //支持Aspectj的静态代理织入 return new String[]{determineTransactionAspectClass()}; default: //其他值则返回null,将会抛出异常 return null; } } private String determineTransactionAspectClass() { return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }

2.1 AutoProxyRegistrar注册自动代理创建者

  AutoProxyRegistrar属于ImportBeanDefinitionRegistrar类型,因此它本身实际上并不会注册到容器中,而是会调用它的registerBeanDefinitions方法,该方法中会尝试注册一个InfrastructureAdvisorAutoProxyCreator自动代理创建者,用于后续创建代理对象。
  目前,只有@EnableCaching和@EnableTransactionManagement注解有可能自动引入AutoProxyRegistrar。因此在方法的第一参数将会传入具有@EnableCaching和@EnableTransactionManagement注解的类的元数据。
  另外还会解析并设置自动代理创建者的proxyTargetClass属性。因此,如果引入类上有多个符合条件的自动代理注解(比如@EnableTransactionManagement、@EnableAsync、@EnableCaching、@EnableAspectJAutoProxy),并且有某个自动代理注解的proxyTargetClass属性设置为true,那么容器中的自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。

/**
 * AutoProxyRegistrar的方法
 * 

* 尝试为自动代理注册一个InfrastructureAdvisorAutoProxyCreator类型的自动代理创建者 * 并且会解析proxyTargetClass属性,如果有某个注解的proxyTargetClass属性设置为true * 那么自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。 * * @param importingClassMetadata 引入该类的类的元数据。目前,只有@EnableCaching和@EnableTransactionManagement注解有可能引入该类 * 因此将会传入,具有@EnableCaching和@EnableTransactionManagement注解的类的元数据 * @param registry bean定义注册表 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; //获取类上的所有注解类型 Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); //循环处理,对于具有mode和proxyTargetClass属性的注解统一处理 for (String annType : annTypes) { //每一个注解的属性集合 AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (candidate == null) { continue; } //获取mode属性 Object mode = candidate.get("mode"); //获取proxyTargetClass属性 Object proxyTargetClass = candidate.get("proxyTargetClass"); /* * 如果存在这两个属性,并且类型也是匹配的 * 很多注解都有这两个属性,比如@EnableTransactionManagement、@EnableAsync、@EnableCaching、@EnableAspectJAutoProxy */ if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { // candidateFound = true; //如果mode值是AdviceMode.PROXY值 if (mode == AdviceMode.PROXY) { /* * 调用AopConfigUtils.registerAutoProxyCreatorIfNecessary方法 * 尝试注册或者升级一个名为"org.springframework.aop.config.internalAutoProxyCreator" * 类型为InfrastructureAdvisorAutoProxyCreator的自动代理创建者的bean定义 */ AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); /* * 如果有某个注解的proxyTargetClass属性设置为true * 那么自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。 */ if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } if (!candidateFound && logger.isInfoEnabled()) { String name = getClass().getSimpleName(); logger.info(String.format("%s was imported but no annotations were found " + "having both 'mode' and 'proxyTargetClass' attributes of type " + "AdviceMode and boolean respectively. This means that auto proxy " + "creator registration and configuration may not have occurred as " + "intended, and components may not be proxied as expected. Check to " + "ensure that %s has been @Import'ed on the same class where these " + "annotations are declared; otherwise remove the import of %s " + "altogether.", name, name, name)); } }

2.2 ProxyTransactionManagementConfiguration注册事务管理bean

  ProxyTransactionManagementConfiguration类是一个@Configuration配置类,将会通过内部的@Bean方法向容器注入一系列与AOP事务相关的一些基础bean定义,包括BeanFactoryTransactionAttributeSourceAdvisor事务通知器、AnnotationTransactionAttributeSource注解事务属性源、TransactionInterceptor事务拦截器、TransactionalEventListenerFactory事务事件监听器工厂

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    /**
     * 注册一个事务通知器bean定义,名为"org.springframework.transaction.config.internalTransactionAdvisor"
     * 类型就是BeanFactoryTransactionAttributeSourceAdvisor
     *
     * @param transactionAttributeSource 事务属性源
     * @param transactionInterceptor     事务拦截器
     */
    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
            TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
        //创建BeanFactoryTransactionAttributeSourceAdvisor
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        //设置属性源
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        //设置通知
        advisor.setAdvice(transactionInterceptor);
        //设置@EnableTransactionManagement注解的order属性
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }


    /**
     * 注册一个事务属性源bean定义,名为"transactionAttributeSource"
     * 类型就是AnnotationTransactionAttributeSource
     */
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    /**
     * 注册一个事务拦截器bean定义,名为"transactionAttributeSource"
     * 类型就是TransactionInterceptor
     *
     * @param transactionAttributeSource 事务属性源
     */
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        //设置事务管理器,这个事务管理器是指通过TransactionManagementConfigurer配置的,而不是通过bean定义的,一般为null
        //所以说通过注解配置的TransactionInterceptor的transactionManager一般都为null,但是没关系,在使用时如果发现为null
        //Spring会查找容器中的TransactionManager的实现来作为事务管理器
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

/**
 * 父类AbstractTransactionManagementConfiguration
 */
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

    @Nullable
    protected AnnotationAttributes enableTx;

    /**
     * 通过TransactionManagementConfigurer配置的默认事务管理器,可以为null
     */
    @Nullable
    protected TransactionManager txManager;

    /**
     * 自动回调方法
     * 用于获取@EnableTransactionManagement注解的属性
     *
     * @param importMetadata 引入当前类的类元数据,就是标注有@EnableTransactionManagement注解的类
     */
    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        //获取引入当前配置类的类上面的@EnableTransactionManagement注解的属性
        this.enableTx = AnnotationAttributes.fromMap(
                importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
        //没有就抛出异常
        if (this.enableTx == null) {
            throw new IllegalArgumentException(
                    "@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
        }
    }

    /**
     * 期望通过TransactionManagementConfigurer的方式注入事务管理器
     * 由于@Autowired的required属性为false,没有TransactionManagementConfigurer的bean的时候,将不会执行该方法
     */
    @Autowired(required = false)
    void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
        //没有就返回
        if (CollectionUtils.isEmpty(configurers)) {
            return;
        }
        //超过一个事务管理器配置类就抛出异常
        if (configurers.size() > 1) {
            throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
        }
        //从事务管理器配置类中获取事务管理器
        TransactionManagementConfigurer configurer = configurers.iterator().next();
        this.txManager = configurer.annotationDrivenTransactionManager();
    }


    /**
     * 注册一个事务事件监听器工厂的bean定义,名为"org.springframework.transaction.config.internalTransactionalEventListenerFactory"
     * 类型就是TransactionalEventListenerFactory
     * 

* 该工厂可以将@TransactionalEventListener注解方法解析为一个ApplicationListenerMethodTransactionalAdapter类型的事件监听器,用于支持事务事件的监听。 */ @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public static TransactionalEventListenerFactory transactionalEventListenerFactory() { return new TransactionalEventListenerFactory(); } }

3 小结

  @EnableTransactionManagement注解用于开启注解事务支持,也就是说如果配置了该注解,那么可以使用基于注解的声明式事务!
  从源码中能看出,该标签会:

  1. @EnableTransactionManagement注解的关键在于内部的@Import注解,该注解尝试向容器注入AutoProxyRegistrar和ProxyTransactionManagementConfiguration两个bean。
  2. AutoProxyRegistrar会尝试注册一个名为org.springframework.aop.config.internalAutoProxyCreator的InfrastructureAdvisorAutoProxyCreator类型的自动代理创建者的bean定义,该bean用于创建代理对象。
    1. 另外还会解析并设置自动代理创建者的proxyTargetClass属性。如果引入类上有多个符合条件的自动代理注解(比如@EnableTransactionManagement、@EnableAsync、@EnableCaching、@EnableAspectJAutoProxy),并且有某个自动代理注解的proxyTargetClass属性设置为true,那么容器中的自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。
  3. ProxyTransactionManagementConfiguration会尝试配置AOP事务相关的一些基础bean定义,包括BeanFactoryTransactionAttributeSourceAdvisor事务通知器、AnnotationTransactionAttributeSource注解事务属性源、TransactionInterceptor事务拦截器、TransactionalEventListenerFactory事务事件监听器工厂!

  总体来说,源码比较简单!如果和前一篇文章Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析的内容进行对比,我们发现它们所做的事都是差不多的,都会尝试注册那些基础bean,这些bean被用于后续Spring 事务的处理逻辑中,我们后面会一一讲到。因此,我们可以说,@EnableTransactionManagement可用于替代<tx:annotation-driven/>标签。

相关文章:
  https://spring.io/
  Spring Framework 5.x 学习
  Spring Framework 5.x 源码

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

你可能感兴趣的:(Spring,5.x,事务源码,Spring事务源码,EnableTransacti,java,事务注解)