一.背景

  前面详解了实现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. Spring框架分为哪七大模块,各模块的主要功能作用是什么

    七大模块,如下: 1. Spring Core: Core封装包是框架的最基础部分,提供IOC和依赖注入特性.这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性 ...

  2. Flutter集成环信IM,发送图片之后渲染conversation.loadMoreMsgFromDB报path为空

    这时会报错,结果如下: 只需在em_message_body下修改如图path为空即可

  3. PHP代码审计学习(1)

    全局变量与超全局变量 $GLOBALS $GLOBALS 是PHP的一个超级全局变量组,在一个PHP脚本的全部作用域中都可以访问,$GLOBALS 是一个包含了全部变量的全局组合数组.变量的名字就是数 ...

  4. jdk环境配置(Windows)

    电脑>属性>高级系统设置>环境变量 1 创建JAVA_HOME,值是你的刚刚jdk的安装目录,比如 C:\Program Files (x86)\Java\jdk1.8.0_101 ...

  5. Vue 属性渲染

    属性渲染 关于标签的属性渲染统一使用v-bind属性指令,比如轮播图的src全部经过后端获得,所以我们需要对src属性做动态渲染. 基本使用 使用v-bind属性指令,动态绑定图片的地址. <b ...

  6. 【Django】将多个querysets拼接,使用djangorestframework序列化

    concern_set = models.Concern.objects.filter(user_id=1).values("concern_id") querysets = mo ...

  7. thinkphp上传图片,生成缩略图

    Image.php <?php /** * 实现图片上传,图片缩小, 增加水印 * 需要定义以下常量 * define('ERR_INVALID_IMAGE', 1); * define('ER ...

  8. 学习篇:NodeJS中的模板引擎:jade

    NodeJS 模板引擎作用:生成页面 在node常用的模板引擎一般是 1.jade --破坏式的.侵入式.强依赖(对原有的html体系不友好,走自己的一套体系)2.ejs --温和的.非侵入式的.弱依 ...

  9. helm部署的服务如何修改配置

    关于helm部署服务 在Kubernetes上进行容器化部署时,使用helm可以简化操作,以部署Jenkins为例,只需要以下命令即可完成部署: helm install --namespace he ...

  10. ThreeJS系列1_CinematicCameraJS插件详解

    ThreeJS系列1_CinematicCameraJS插件详解 接着上篇 ThreeJS系列1_CinematicCameraJS插件介绍 看属性的来龙去脉 看方法作用 通过调整属性查看效果 总结 ...