`

自定义方法注解实现事务完成后执行方法

 
阅读更多

     起因:有时候我们有这样的需求,在一个事务方法中调用了其他类的某个方法,但希望这个方法再事务提交后执行。

       思考:被调用的方法,肯定要做到延迟执行,可以把执行的方法放入ThreadLocal里,等事务提交后拿出来执行,但怎么判断事务已经提交了呢,这个就要用到spring 事务处理的AbstractPlatformTransactionManager类里面的回调功能

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
  try {
   boolean beforeCompletionInvoked = false;
   try {
    prepareForCommit(status);
    triggerBeforeCommit(status);
    triggerBeforeCompletion(status);
    beforeCompletionInvoked = true;
    boolean globalRollbackOnly = false;
    if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
     globalRollbackOnly = status.isGlobalRollbackOnly();
    }
    if (status.hasSavepoint()) {
     if (status.isDebug()) {
      logger.debug("Releasing transaction savepoint");
     }
     status.releaseHeldSavepoint();
    }
    else if (status.isNewTransaction()) {
     if (status.isDebug()) {
      logger.debug("Initiating transaction commit");
     }
     doCommit(status);
    }
    // Throw UnexpectedRollbackException if we have a global rollback-only
    // marker but still didn't get a corresponding exception from commit.
    if (globalRollbackOnly) {
     throw new UnexpectedRollbackException(
       "Transaction silently rolled back because it has been marked as rollback-only");
    }
   }
   catch (UnexpectedRollbackException ex) {
    // can only be caused by doCommit
    triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
    throw ex;
   }
   catch (TransactionException ex) {
    // can only be caused by doCommit
    if (isRollbackOnCommitFailure()) {
     doRollbackOnCommitException(status, ex);
    }
    else {
     triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
    }
    throw ex;
   }
   catch (RuntimeException ex) {
    if (!beforeCompletionInvoked) {
     triggerBeforeCompletion(status);
    }
    doRollbackOnCommitException(status, ex);
    throw ex;
   }
   catch (Error err) {
    if (!beforeCompletionInvoked) {
     triggerBeforeCompletion(status);
    }
    doRollbackOnCommitException(status, err);
    throw err;
   }

   // Trigger afterCommit callbacks, with an exception thrown there
   // propagated to callers but the transaction still considered as committed.
   try {
    triggerAfterCommit(status);
   }
   finally {
    triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
   }

  }
  finally {
   cleanupAfterCompletion(status);
  }
 }

 上面的trtriggerAfterCommit(status);就是处理事务提交后的动作处理,继续跟踪发现是调用

TransactionSynchronizationUtils 的下面方法

public static void invokeAfterCommit(List<TransactionSynchronization> synchronizations) {
  if (synchronizations != null) {
   for (TransactionSynchronization synchronization : synchronizations) {
    synchronization.afterCommit();
   }
  }
 }

synchronizations参数是通过 TransactionSynchronizationManager.getSynchronizations()获得的真是从ThreadLoca获取的对象是TransactionSynchronization。

 

 

  解决方法:自定义注解,在切面拦截有注解 的方法,并把待调用的方法封装到下面的这个类里并且执行execute方法,把当前方法设置到TransactionSynchronizationManager。最后再回调方法执行。

 

public class AfterCommitExecutorImpl extends TransactionSynchronizationAdapter implements AfterCommitExecutor {
    private static final Logger LOGGER = Logger.getLogger(AfterCommitExecutorImpl.class);
    private static final ThreadLocal<List<Runnable>> RUNNABLES = new ThreadLocal<List<Runnable>>();

    @Override
    public void execute(Runnable runnable) {
        LOGGER.info("Submitting new runnable {"+runnable+"} to run after commit");
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            LOGGER.info("Transaction synchronization is NOT ACTIVE. Executing right now runnable {"+runnable+"}");
            runnable.run();
            return;
        }
        List<Runnable> threadRunnables = RUNNABLES.get();
        if (threadRunnables == null) {
            threadRunnables = new ArrayList<Runnable>();
            RUNNABLES.set(threadRunnables);
            TransactionSynchronizationManager.registerSynchronization(this);
        }
        threadRunnables.add(runnable);
    }

    @Override
    public void afterCommit() {
        List<Runnable> threadRunnables = RUNNABLES.get();
        LOGGER.info("Transaction successfully committed, executing {"+threadRunnables.size()+"} runnables" );
        for (int i = 0; i < threadRunnables.size(); i++) {
            Runnable runnable = threadRunnables.get(i);
            LOGGER.info("Executing runnable {"+runnable+"}");
            try {
                runnable.run();
            } catch (RuntimeException e) {
                LOGGER.error("Failed to execute runnable " + runnable, e);
            }
        }
    }

    @Override
    public void afterCompletion(int status) {
        LOGGER.info("Transaction completed with status {"+(status == STATUS_COMMITTED ? "COMMITTED" : "ROLLED_BACK")+"}");
        RUNNABLES.remove();
    }

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Spring高级之注解驱动开发视频教程

    AOP是让方法间的各个部分更加独立,达到统一调用执行,使后期维护更加的方便。 SpringMVC本身是对Servlet和JSP的API进行了封装,同时在此基础上进一步加强。它推出的一套注解,可以降低开发人员的学习成本,从而更...

    Aspect自定义springboot的使用.docx

    在Spring AOP中,切面通过常规类(基本模式方法)或者通过使用了注解@Aspect的常规类来实现。 连接点(Joint point):是指在程序执行期间的一个点,比如某个方法的执行或者是某个异常的处理。在Spring AOP中,一个...

    SpringBoot+Mybatis实现数据源动态切换

    springboot实现数据源动态切换 注意事项: 1. 该demo采用yml配置数据库信息,注意url标签为jdbc-url 2.项目中加了日志输出...3.在Service中应用事务时,自定义的注解将失效,解决办法:可将注解配置到Controller方法中

    MethodBoundaryAspect.Fody:Fody编织者,它可以修饰方法并挂接到方法开始,方法结束和方法异常中

    一些自定义对象,可以在方法开始时设置该对象,并在该方法结束时进行访问(例如,对于事务或计时器有用) 在不同级别应用方面 在AssemblyInfo.cs全局 上课 上方法 更改方法行为(请参见下面的示例) 覆盖输入参数...

    mavenssm maven spring3 struts2 mybaits

    5 任务调度 可以实现自定义一个任务在XML中 隔多长时间执行一次 把jar包注掉了 6 实现了一个ztree 压缩包里有一个说明文件 可以看一下 pom xml冲突是件挺恶心的事儿 还有就是 遇到了导入myeclipse里 resource文件...

    fat:基于springboot,zookeeper,redis分布式事务强一致性方案

    脂肪FAT,基于springboot,使用zookeeper,...同时具有一定的扩展性与兼容性,因为存在自定义的服务框架,或者以后会涌现出更多的流行分布式服务框架,所以会提供一些组件适应自定义服务框架。Maven依赖&lt; depende

    Spring.3.x企业应用开发实战(完整版).part2

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    Spring3.x企业应用开发实战(完整版) part1

    Spring3.0是Spring在积蓄了3年之久后,隆重推出的一个重大升级版本,进一步加强了Spring作为Java领域第一开源平台的翘楚地位。  Spring3.0引入了众多Java开发者翘首以盼的新功能和新特性,如OXM、校验及格式化框架...

    基于springboot , zookeeper , redis 分布式事务强一致性方案+源代码+文档说明

    在需要开启分布式事务管理的入口方法中加入注解@FatServiceRegister,注意不要重复添加。dubbo的直接加在serviceImpl.method上面就可以 ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的...

    企业后台管理基础框架 hsweb.zip

    模块设置: 配合动态表单实现表格页,查询条件自定义.数据库维护: 在线维护数据库,修改表结构,执行sql.数据源管理: 配置多数据源.代码生成器: 在线生成代码,打包下载.可自定义模板.定时任务: 配置定时任务,使用动态...

    spring.net中文手册在线版

    14.5.1.理解Spring.NET声明式事务管理的实现 14.5.2.第一个例子 14.5.3.Transaction特性的设置 14.5.4.通过AutoProxyCreator使用声明式事务 14.5.5.通过TransactionProxyFactoryObject使用声明式事务 14.5.6. 通过...

    spring-boot mybaits shiro redis整合

    Transtraction注解Jta事务。 3、MVC ====== 基于spring mvc注解。Exception统一管理。 shiro权限管理。 aop日志记录。 4、调度 ====== Spring task, 可以查询已经注册的任务。立即执行一次任务。 5、缓存和...

    springboot参考指南

    1. 介紹 2. I. Spring Boot文档 i. 1....ii. 2....iii....iv....v....vi....vii....3. II....i....ii....i....iii....i....i....ii....ii....i....ii....iii....iv....v.... 命令行实现 vi....iii....iv.... 自定义'白标'(whitelabel,可以了解下相关理念)错误页面 x. 71...

    Spring中文帮助文档

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    Spring API

    9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. &lt;tx:advice/&gt; 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...

    lamp-cloud微服务脚手架

    基于Mybatis-plus-generator自定义了一套代码生成器, 通过配置数据库字段的注释,自动生成枚举类、数据字典注解、SaveDTO、UpdateDTO、表单验证规则注解、Swagger注解等。 16、定时任务调度器: 基于xxl-jobs进行了...

    javaSE代码实例

    1.2.3 安装后Java目录的解读 7 1.3 学会使用API 7 1.4 第一个Java程序 8 1.4.1 开发源代码 8 1.4.2 编译运行 9 1.5 小结 11 第2章 基本数据类型——构建Java 大厦的基础 12 2.1 源代码注释 12 ...

    Spring攻略(第二版 中文高清版).part2

    2.11 创建Bean后处理器 85 2.11.1 问题 85 2.11.2 解决方案 85 2.11.3 工作原理 86 2.12 外部化Bean配置 89 2.12.1 问题 89 2.12.2 解决方案 89 2.12.3 工作原理 90 2.13 解析文本消息 91 2.13.1...

    Spring攻略(第二版 中文高清版).part1

    2.11 创建Bean后处理器 85 2.11.1 问题 85 2.11.2 解决方案 85 2.11.3 工作原理 86 2.12 外部化Bean配置 89 2.12.1 问题 89 2.12.2 解决方案 89 2.12.3 工作原理 90 2.13 解析文本消息 91 2.13.1...

Global site tag (gtag.js) - Google Analytics