• Spring笔记(5)


    一.背景

      前面详解了实现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;
                  }
              }
          } 
  • 相关阅读:
    C#获取当前程序运行路径的方法集合
    SQL为查询的结果加上序号(ROW_NUMBER) 合并多个查询结果
    Asp.net导出excel时长数字被科学计数法的解决方案。(身份证长数字作为字符处理)
    Stopwatch的用法
    对web.config的ConnectionString加密
    如何检索数据库中的空值和null
    如何将闲置的平板作为第二显示器(分屏)使用
    pyinstaller 打包文件太大
    如何让openssl生成的SSL证书被浏览器认可
    还是那该死的IE~~~
  • 原文地址:https://www.cnblogs.com/huangrenhui/p/13849553.html
Copyright © 2020-2023  润新知