一.背景

  前面详解了实现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. TypeScript之父:JS不是竞争对手,曾在惧怕开源的微软文化中艰难求生

    开源的 TypeScript 也曾在微软内部遭到抵制,但如今 TypeScript 已经成为 Web 应用构建的主流语言.   微软的开源编程语言 TypeScript 是 JavaScript 的一 ...

  2. Flutter继承环信IM-发送视频时失败:No value for fileLength

    首先贴一下代码: 这是发送视频消息的方法 报出一下错误信息: 这是由于在解析的时候JSON里面没有fileLength这个值 往回看发送视频消息api,也并不需要fileLength参数 那顺着错误信 ...

  3. springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器 和错误跳转自定页面

    测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git DispatcherServlet ...

  4. Android 自定义Vie 对勾CheckBox

    天在美团点外卖,有一个商品推荐的条目,上面的CheckBox是自定义的,虽然我们大部分都是用图片来自定义样式.但是还是可以自定义View来绘制的,只要画一个圆和对勾即可. 最终效果 最终效果.png ...

  5. 手把手撸套框架-Victory框架1.1 详解

    目录 上一篇博客 Victory框架1.0 详解  有说道,1.0的使用过程中出现不少缺点,比如菜单不能折叠,权限没有权限组等等. 所以,我还是抽出时间在下班后,回到我的小黑屋里 完成了1.1的升级. ...

  6. 设计模式PDF下载了4.0万本!那,再肝一本《Java面经手册》吧!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 1. 先祝贺下自己拿下4.0万本下载量! <重学Java设计模式>PDF ...

  7. 什么是64位和32位internet explorer

    什么是64位和32位internet explorer 如果您使用 64 位版本的 Internet Explorer 时,您会遇到问题,请尝试使用 32 位版本的 Internet Explorer ...

  8. 《VC++ 深入详解》 第3版 这是盗版书么~。。。

    <VC++ 深入详解> 第3版 www.broadview.com.cn 书读到一小半,发现书重复了一部分,缺失一部分.... 难受~ 比较难继续下去了 有一样的小伙伴么~ <VC+ ...

  9. Android设备上的逐像素碰撞检测

    介绍 我正在我的Android设备上开发一款游戏,不用说,因为我想要接触到尽可能多的用户,我做到了 省略了硬件加速.因此,我需要编写能够在大多数设备上运行的最快的代码.我从一个简单的表面视图开始 并使 ...

  10. 2. 在TCGA中找到并下载意向数据

    听说过别人用生信分析"空手套白狼"的故事吧想做吗好想学哦~ 或多或少都知道GEO和TCGA这些公共数据库吧!那么你知道怎么在数据库上找到意向数据,并且成功下载呢?这第一步要难倒一大 ...