一.背景

  前面详解了实现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. win10 系统出现“你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问。”

    公司无法访问共享 \192.168.7.101.win+R 输入gpedit.msc2.计算机配置-管理模板–网络-lanman 工作站-找到"启用不安全的来宾登录"选择 已启用. ...

  2. HTML自学第一篇

    教程来自W3CSchool 因为笔者有过开发经验 本篇只是个人对HTML自学的笔记,可能不适合用于给他人理解和学习 什么是 HTML HTML 指的是超文本标记语言 (Hyper Text Marku ...

  3. JVM学习(六)JVM常见知识问答

    文章更新时间:2020/04/21 1.什么是Java虚拟机?为什么Java被称作是"平台无关的编程语言"? Java虚拟机是一个可以执行Java字节码的虚拟机进程. Java源文 ...

  4. Ubuntu中卸载node和npm并重装

    1.node 和 npm 卸载不干净 #apt-get 卸载 sudo apt-get remove --purge npm sudo apt-get remove --purge nodejs su ...

  5. CUP的MESI协议

    MESI协议中的状态 CPU中每个缓存行(caceh line)使用4种状态进行标记(使用额外的两位(bit)表示): M: 被修改(Modified) 该缓存行只被缓存在该CPU的缓存中,并且是被修 ...

  6. [论文理解] Good Semi-supervised Learning That Requires a Bad GAN

    Good Semi-supervised Learning That Requires a Bad GAN 恢复博客更新,最近没那么忙了,记录一下学习. Intro 本文是一篇稍微偏理论的半监督学习的 ...

  7. C# Redis分布式锁 - 单节点

    为什么要用分布式锁? 先上一张截图,这是在浏览别人的博客时看到的. 在了解为什么要用分布式锁之前,我们应该知道到底什么是分布式锁. 锁按照不同的维度,有多种分类.比如 1.悲观锁,乐观锁; 2.公平锁 ...

  8. C\C++中strcat()函数

    转载:https://blog.csdn.net/smf0504/article/details/52055971 C\C++中strcat()函数                           ...

  9. 15.深入k8s:Event事件处理及其源码分析

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 源码版本是1.19 概述 k8s的Event事件是一种资源对象,用于展示集群内发生的情况 ...

  10. Vue3实战系列:结合 Ant-Design-of-Vue 实践 Composition API

    Vue 3 出来之后,很多人有如下想法,"又要学新东西啦"."我学不动了"等等. 但是事物总有它的两面性,前端知识更新的很快,利好勤奋好学的同学.计算机行业的迭 ...