Spring筆記(5) - 聲明式事務@EnableTransactionManagement註解源碼分析

一.背景

  前面詳解了實現Spring事務的兩種方式的不同實現:編程式事務和聲明式事務,對於配置都使用到了xml配置,今天介紹Spring事務的註解開發,例如下面例子:

  1. 配置類:註冊數據源、JDBC模板、事務管理器
    //包掃描,將包下的dao、service註冊到Spring容器中
    @ComponentScan("com.hrh")
    //開啓基於註解的事務管理,跟@Transactional註解配套使用
    @EnableTransactionManagement
    //表明TxConfig是配置類
    @Configuration
    public class TxConfig {
        //註冊數據源
        @Bean
        public DataSource dataSource() throws Exception {
            ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
            comboPooledDataSource.setUser("xxx");
            comboPooledDataSource.setPassword("xxx");
            comboPooledDataSource.setJdbcUrl("jdbc:mysql://xxx:3306/xxx");
            comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
            return comboPooledDataSource;
        }
    
        //註冊jdbc模板
        @Bean
        public JdbcTemplate jdbcTemplate() throws Exception {
            return new JdbcTemplate(dataSource());
        }
    
        //註冊事務管理器來控制事務
        @Bean
        public PlatformTransactionManager manager() throws Exception {
            return new DataSourceTransactionManager(dataSource());
        }
    }
  2. 業務代碼:
    @Repository
    public class UserDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
        public void insert(){
            String sql ="insert into tab_person(name,age) values(?,?)";
            String name = UUID.randomUUID().toString().substring(0, 5);
            jdbcTemplate.update(sql,name,19);
        }
    }
    
    @Service
    public class UserService{
        @Autowired
        private UserDao userDao;
        
        //添加事務
        @Transactional
        public void insert() {
            userDao.insert();
            System.out.println("插入完成。");
            int i = 10/0;
        }
    }
  3. 測試:從下面運行結果可以看出拋出了異常,在數據庫中查看數據發現沒有最新的數據插入,表明插入操作進行了回滾
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
            UserService bean = context.getBean(UserService.class);
            bean.insert();
            context.close();
        }
        
    運行結果:
        
        插入完成。
        Exception in thread "main" java.lang.ArithmeticException: / by zero
            at com.hrh.service.UserService.insert(UserService.java:20) 

 二. @EnableTransactionManagement註解源碼分析

  1.流程

    1. EnableTransactionManagement導入一個TransactionManagementConfigurationSelector組件

    2. TransactionManagementConfigurationSelector默認導入兩個組件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration

    3. AutoProxyRegistrar(利用後置處理器包裝代理對象):註冊一個InfrastructureAdvisorAutoProxyCreator組件(自動代理創建器),利用後置處理器機制在對象創建之後包裝對象,返回一個代理對象(增強器),利用攔截器鏈執行方法

    4. ProxyTransactionManagementConfiguration(註冊配置):給容器註冊各種組件,註冊了事務增強器

        4.1)事務增強器要用事務註解的信息,AnnotationTransactionAttributeSource解析了註解上的各種屬性信息

        4.2)同時用到TransactionInterceptor事務攔截器:保存了事務屬性信息、事務管理器

          4.2.1)在目標方法執行時:執行攔截器鏈(即TransactionInterceptor)

            4.2.2)TransactionInterceptor事務攔截器的作用:獲取事務相關的屬性,再獲取事務管理器進行事務的執行、回滾或提交操作;

  2.源碼解析

    1.  EnableTransactionManagement導入一個TransactionManagementConfigurationSelector組件
      @Import({TransactionManagementConfigurationSelector.class})
      public @interface EnableTransactionManagement {
          //默認爲false
          boolean proxyTargetClass() default false;
          //默認爲PROXY
          AdviceMode mode() default AdviceMode.PROXY;
      
          int order() default 2147483647;
      }
    2. TransactionManagementConfigurationSelector默認導入兩個組件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
      public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
          //AdviceMode值在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;
              }
          }
      
      }
    3. AutoProxyRegistrar(利用後置處理器包裝代理對象):註冊一個InfrastructureAdvisorAutoProxyCreator組件(自動代理創建器),利用後置處理器機制在對象創建之後包裝對象,返回一個代理對象(增強器),利用攔截器鏈執行方法
      public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
      
          @Override
          public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
              boolean candidateFound = false;
              Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
              for (String annType : annTypes) {
                  AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
                  if (candidate == null) {
                      continue;
                  }
                  Object mode = candidate.get("mode");
                  Object proxyTargetClass = candidate.get("proxyTargetClass");
                  if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                          Boolean.class == proxyTargetClass.getClass()) {
                      candidateFound = true;
                      //註冊一個InfrastructureAdvisorAutoProxyCreator組件(自動代理創建器)
                      if (mode == AdviceMode.PROXY) {
                          AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                          //proxyTargetClass在EnableTransactionManagement默認false
                          if ((Boolean) proxyTargetClass) {
                              AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                              return;
                          }
                      }
                  }
              }
              .....
          }
      
      }
      • AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry):自動代理創建器
        public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
                return registerAutoProxyCreatorIfNecessary(registry, null);
            }
        
            @Nullable
            public static BeanDefinition registerAutoProxyCreatorIfNecessary(
                    BeanDefinitionRegistry registry, @Nullable Object source) {
                //給容器註冊InfrastructureAdvisorAutoProxyCreator(是一個後置處理器),利用後置處理器機制在對象創建之後包裝對象,返回一個代理對象(增強器),利用攔截器鏈執行方法
                return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
            }
    4. ProxyTransactionManagementConfiguration(註冊配置):給容器註冊各種組件,註冊了事務增強器
      @Configuration
      public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
          //註冊事務增強器BeanFactoryTransactionAttributeSourceAdvisor
          @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
          @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
          public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
              BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
              //設置事務屬性,從註解解析器獲取註解上的事務屬性值
              advisor.setTransactionAttributeSource(transactionAttributeSource());
              //設置了TransactionInterceptor事務攔截器
              advisor.setAdvice(transactionInterceptor());
              advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
              return advisor;
          }
          //註冊事務屬性,解析註解中的各種屬性,比如propagation、isolation、timeout等
          @Bean
          @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
          public TransactionAttributeSource transactionAttributeSource() {
              //註解解析器
              return new AnnotationTransactionAttributeSource();
          }
          //註冊了TransactionInterceptor事務攔截器:保存了事務屬性信息、事務管理器
          @Bean
          @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
          public TransactionInterceptor transactionInterceptor() {
              TransactionInterceptor interceptor = new TransactionInterceptor();
              //保存了事務屬性信息
              interceptor.setTransactionAttributeSource(transactionAttributeSource());
              if (this.txManager != null) {
                  //保存了事務管理器
                  interceptor.setTransactionManager(this.txManager);
              }
              return interceptor;
          }
      
      }
      1. 註解解析器AnnotationTransactionAttributeSource
        public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
            this.publicMethodsOnly = publicMethodsOnly;
            this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(4);
            //添加spring事務註解的解析器
            this.annotationParsers.add(new SpringTransactionAnnotationParser());
            if (jta12Present) {
                //添加jta事務註解的解析器
                this.annotationParsers.add(new JtaTransactionAnnotationParser());
            }
            if (ejb3Present) {
                //添加Ejb3事務註解的解析器
                this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
            }
        }
        public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
            AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
                    element, Transactional.class);
            if (attributes != null) {
                //解析註解
                return parseTransactionAnnotation(attributes);
            }
            else {
                return null;
            }
        }
        //解析註解Transactional上的每個屬性
        protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
            RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        
            Propagation propagation = attributes.getEnum("propagation");
            rbta.setPropagationBehavior(propagation.value());
            Isolation isolation = attributes.getEnum("isolation");
            rbta.setIsolationLevel(isolation.value());
            rbta.setTimeout(attributes.getNumber("timeout").intValue());
            rbta.setReadOnly(attributes.getBoolean("readOnly"));
            rbta.setQualifier(attributes.getString("value"));
        
            List<RollbackRuleAttribute> rollbackRules = new ArrayList<RollbackRuleAttribute>();
            for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
                rollbackRules.add(new RollbackRuleAttribute(rbRule));
            }
            for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
                rollbackRules.add(new RollbackRuleAttribute(rbRule));
            }
            for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
                rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
            }
            for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
                rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
            }
            rbta.setRollbackRules(rollbackRules);
        
            return rbta;
        }
      2. 事務攔截器TransactionInterceptor:是一個MethodInterceptor,方法攔截器(4個通知方法整合成了增強器,增強器整合成了MethodInterceptor。我們在容器中放置了一個代理對象,當要執行代理對象時,方法攔截器就執行了)
        public Object invoke(final MethodInvocation invocation) throws Throwable {
            // Work out the target class: may be {@code null}.
            // The TransactionAttributeSource should be passed the target class
            // as well as the method, which may be from an interface.
            Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        
            // Adapt to TransactionAspectSupport's invokeWithinTransaction...
            return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
                @Override
                public Object proceedWithInvocation() throws Throwable {
                    return invocation.proceed();
                }
            });
        }
        protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
                throws Throwable {
        
            // If the transaction attribute is null, the method is non-transactional.
            //獲取事務屬性
            final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
            //獲取事務管理器
            final PlatformTransactionManager tm = determineTransactionManager(txAttr);
            //獲取執行的事務方法
            final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
        
            if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
                // Standard transaction demarcation with getTransaction and commit/rollback calls.
                //開啓事務
                TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
                Object retVal = null;
                try {
                    // This is an around advice: Invoke the next interceptor in the chain.
                    // This will normally result in a target object being invoked.
                    //事務方法執行
                    retVal = invocation.proceedWithInvocation();
                }
                catch (Throwable ex) {
                    // target invocation exception
                    //事務異常會獲取事務管理器,利用事務管理器執行回滾操作
                    completeTransactionAfterThrowing(txInfo, ex);
                    throw ex;
                }
                finally {
                    cleanupTransactionInfo(txInfo);
                }
                //如果正常,利用事務管理器提交事務
                commitTransactionAfterReturning(txInfo);
                return retVal;
            }
        
            else {
                final ThrowableHolder throwableHolder = new ThrowableHolder();
        
                // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
                try {
                    Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
                            new TransactionCallback<Object>() {
                                @Override
                                public Object doInTransaction(TransactionStatus status) {
                                    TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
                                    try {
                                        return invocation.proceedWithInvocation();
                                    }
                                    catch (Throwable ex) {
                                        if (txAttr.rollbackOn(ex)) {
                                            // A RuntimeException: will lead to a rollback.
                                            if (ex instanceof RuntimeException) {
                                                throw (RuntimeException) ex;
                                            }
                                            else {
                                                throw new ThrowableHolderException(ex);
                                            }
                                        }
                                        else {
                                            // A normal return value: will lead to a commit.
                                            throwableHolder.throwable = ex;
                                            return null;
                                        }
                                    }
                                    finally {
                                        cleanupTransactionInfo(txInfo);
                                    }
                                }
                            });
        
                    // Check result state: It might indicate a Throwable to rethrow.
                    if (throwableHolder.throwable != null) {
                        throw throwableHolder.throwable;
                    }
                    return result;
                }
                catch (ThrowableHolderException ex) {
                    throw ex.getCause();
                }
                catch (TransactionSystemException ex2) {
                    if (throwableHolder.throwable != null) {
                        logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                        ex2.initApplicationException(throwableHolder.throwable);
                    }
                    throw ex2;
                }
                catch (Throwable ex2) {
                    if (throwableHolder.throwable != null) {
                        logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
                    }
                    throw ex2;
                }
            }
        } 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章