一.背景

  前面详解了实现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;
        }
        }

Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析的更多相关文章

  1. Spring学习笔记3—声明式事务

    1 理解事务 事务:在软件开发领域,全有或全无的操作被称为事务.事务允许我们将几个操作组合成一个要么全部发生要么全部不发生的工作单元. 事务的特性: 原子性:事务是由一个或多个活动所组成的一个工作单元 ...

  2. Spring—SSJ集成&声明式事务管理

    1.   课程介绍 1.  SSJ集成;(掌握) 2.  声明式事务管理;(掌握) 什么是三大框架 2.1.  ssh Struts/Struts2 Spring Hibernate 2.2.  ss ...

  3. Spring PropertyResolver 占位符解析(二)源码分析

    Spring PropertyResolver 占位符解析(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) ...

  4. Spring Boot启动命令参数详解及源码分析

    使用过Spring Boot,我们都知道通过java -jar可以快速启动Spring Boot项目.同时,也可以通过在执行jar -jar时传递参数来进行配置.本文带大家系统的了解一下Spring ...

  5. Spring的声明式事务----Annotation注解方式(2)

    使用步骤: 步骤一.在spring配置文件中引入<tx:>命名空间<beans xmlns="http://www.springframework.org/schema/b ...

  6. spring学习笔记(22)声明式事务配置,readOnly无效写无异常

    在上一节内容中.我们使用了编程式方法来配置事务,这种优点是我们对每一个方法的控制性非常强.比方我须要用到什么事务,在什么位置假设出现异常须要回滚等.能够进行非常细粒度的配置.但在实际开发中.我们可能并 ...

  7. Spring学习笔记:声明式事务管理增删改查业务

    一.关于是事务 以方法为单位,进行事务控制:抛出异常,事务回滚. 最小的执行单位为方法.决定执行成败是通过是否抛出异常来判断的,抛出异常即执行失败 二.声明式事务: 声明式事务(declarative ...

  8. SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务

    一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...

  9. spring4声明式事务--01注解方式

    1.在spring配置文件中引入 tx 命名空间 xmlns:tx="http://www.springframework.org/schema/tx" 2.配置事务管理器 < ...

随机推荐

  1. 论文阅读笔记: Natural Language Inference over Interaction Space

    这篇文章提出了DIIN(DENSELY INTERACTIVE INFERENCE NETWORK)模型. 是解决NLI(NATURAL LANGUAGE INFERENCE)问题的很好的一种方法. ...

  2. CVE-2018-8045

    Joomla!Core SQL注入漏洞 CVE-2018-8045 受影响版本:joomla!3.5.0-3.8.5 漏洞描述: joomla!3.5.0-3.8.5版本对sql语句内的变量缺少类型转 ...

  3. 使用eclipse启动tomcat,正常模式下可以启动tomcat,却在debug模式下无法启动tomcat 问题解决

    这个问题可能是由于eclipse和tomcat的交互而产生的,在以debug模式启动tomcat时,发生了读取文件错误,eclipse自动设置了断点,导致tomcat不能正常启动. 解决方法把brea ...

  4. Token机制,session机制

    对于初学者来说,对Token和Session的使用难免会限于困境,开发过程中知道有这个东西,但却不知道为什么要用他? session机制:就是一个id号(cookie里面携带一个sessionid), ...

  5. 剑指offer-二叉树

    1. 平衡二叉树 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 解: 要么是一颗空树,要么左右子树都是平衡二叉树且左右子树深度之差不超过1 1 # class TreeNode: 2 # def _ ...

  6. 【小白学PyTorch】18 TF2构建自定义模型

    [机器学习炼丹术]的炼丹总群已经快满了,要加入的快联系炼丹兄WX:cyx645016617 参考目录: 目录 1 创建自定义网络层 2 创建一个完整的CNN 2.1 keras.Model vs ke ...

  7. 【题解】CF1228D Complete Tripartite

    Link 题目大意:给定一个无向图,将它划分为三个点集,要求在一个点集中的点没有边相连,且颜色相同,不同集合中的点互相有边相连. \(\text{Solution:}\) 我们发现,与一个点之间没有边 ...

  8. 「DevOps 转型与实践」沙龙回顾第一讲

    9 月 19 日,CODING 和中国 DevOps 社区联合举办的深圳第九届 Meetup 在腾讯大厦 2 楼多功能圆满结束.本次沙龙以 「DevOps 转型与实践」 为主题,4 位来自互联网.金融 ...

  9. Springcloud技术分享

    Springcloud技术分享 Spring Cloud 是一套完整的微服务解决方案,基于 Spring Boot 框架,准确的说,它不是一个框架,而是一个大的容器,它将市面上较好的微服务框架集成进来 ...

  10. CyclicBarrier原来是这样的

    上一篇聊了一下Semaphore信号灯的用法及源码,这一篇来聊一下CyclicBarrier的用法及解析. 官网解释: 允许一组线程全部等待彼此达到共同屏障点的同步辅助.循环阻塞在涉及固定大小的线程方 ...