`

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

 
阅读更多

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

       思考:被调用的方法,肯定要做到延迟执行,可以把执行的方法放入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自定义注解样例

    System.out.println("在执行方法后,处理自定义注解:" + customAnnotation.value()); return result; } } ``` 在这个例子中,`@Around("@annotation(customAnnotation)")`表示我们的通知将在标记了`Custom...

    SpringMVC利用AOP实现自定义注解记录日志

    // 方法执行后记录日志 long elapsedTime = System.currentTimeMillis() - start; System.out.println("方法结束,执行时间:" + elapsedTime + "ms"); return result; } catch (Exception e) { // 记录异常...

    SpringBoot AOP各种注解、自定义注解、鉴权使用案例(免费下载)

    `@Before`、`@After`、`@AfterReturning`、`@AfterThrowing`和`@Around`分别代表在方法执行前、执行后(无论是否成功)、正常返回后、抛出异常后和环绕方法执行时运行的代码。 例如,我们可以使用`@Before`注解实现...

    spring boot注解事务+多线程

    首先,让我们关注"注解事务"。在Spring框架中,我们主要依赖`@Transactional`注解来声明事务边界。当一个方法被这个注解标记时,Spring会自动管理事务的开始、提交或回滚。如果方法中发生任何未捕获的异常,事务将被...

    springboot 脱敏自定义注解

    在Spring Boot应用中,我们可以通过自定义注解和Spring AOP(面向切面编程)来实现这一功能。下面将详细解释这个主题。 首先,了解Spring AOP的概念。AOP是面向切面编程,它允许我们在不修改源代码的情况下,通过预...

    Spring自定义切面事务问题

    - **通过`order`属性调整切面的优先级**:为了确保事务能够正常工作,我们需要保证事务管理器切面的执行优先级高于其他自定义切面。这可以通过设置`order`属性来实现。`order`值越小,表示优先级越高。 4. **示例...

    Spring AOP 自定义注解的实现代码

    在文章中,使用 AspectJ 来织入自定义注解 SecureValid,以便在方法执行前后执行相应的处理逻辑。 Spring AOP 自定义注解的实现代码中还涉及到 Maven 依赖管理、spring-aop 和 aspectjrt 等库的使用。这些库提供了...

    自定义注解案例

    - AOP切面:`@Transactional`指定方法应在事务中执行。 在TestAnnotation项目中,你可以找到一个具体的自定义注解案例,包括注解的定义、使用和通过反射进行解析的示例代码。通过研究这个案例,你将更深入地理解...

    java 自定义注解

    Java自定义注解是Java平台提供的一种元数据机制,它允许程序员在代码中添加额外的信息,这些信息可以被编译器、JVM或其他工具在编译时或运行时读取,用于实现各种功能,如代码生成、代码分析、依赖注入等。自定义...

    自定义注解MVC

    - 自定义注解可以结合AOP实现切面,如`@Before`、`@After`、`@Around`等,定义在哪些方法之前、之后或环绕执行特定操作。 6. **实例应用** - 创建一个自定义的`@MyController`注解,用于标记控制器类,然后编写...

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    自定义事务管理器需要实现`PlatformTransactionManager`接口,并提供开始、提交、回滚事务的方法。同时,你可以定义自定义的事务注解,以实现更灵活的事务控制。 例如,假设你创建了一个名为`...

    mybatis自定义注解完成数据库切库

    为了实现数据库切库,我们需要创建一个自定义注解,用于标记需要切换数据库的方法,并编写相应的拦截器来处理这些注解。 1. **创建自定义注解**: 创建一个新的Java注解,例如`@DatabaseSwitch`,它包含一个属性,...

    Spring+SpringMvc+MybatisPlus+Aop(自定义注解)动态切换数据源

    自定义注解可以附加在方法上,当该方法被调用时,AOP会捕获这个调用并执行相应的逻辑,即切换到指定的数据源。 具体实现步骤如下: 1. 定义数据源配置:创建多个DataSource配置,每个数据源对应不同的数据库连接...

    SpringBoot 、Shiro、 自定义注解权限控制源码下载

    例如,通过Shiro的自定义注解,可以在方法级别进行权限判断,确保只有具有特定权限的用户才能执行特定的操作。这在描述中提到的"自定义注解权限控制"就是指这一功能。 MyBatis Plus则是在MyBatis的基础上扩展的一套...

    注解版本声明事务小例子

    1. **注解方式声明事务**:Spring提供了`@Transactional`注解,可以将其添加到方法级别或类级别,以声明该方法或类需要在事务上下文中执行。例如: ```java @Service public class UserService { @Transactional ...

    spring自定义注解实现拦截器的实现方法

    总结起来,通过定义一个自定义注解来标记需要拦截的方法,并通过AOP配置来指定拦截器的执行时机和方法,可以灵活地在Spring MVC应用中添加各种前置处理逻辑,而不影响核心业务代码的清晰和专注。这种方式不仅可以...

    借助spring自定义命令执行器

    自定义命令执行器就是一种实现业务解耦的方式,它提供了一个通用的接口,用于执行各种特定任务,而不是直接引用具体的业务类或方法。 2. **命令执行器**:命令执行器是一个设计模式,它的核心思想是将命令(即方法...

    谈谈Java中自定义注解及使用场景

    通过在控制器方法上使用自定义注解,拦截器可以检测并执行相应的逻辑,例如检查用户是否已登录。 2. **注解+AOP(面向切面编程)** 自定义注解可以与Spring AOP结合,用于实现特定的切面逻辑。例如,可以创建一个`...

    spring 事务基于注解模式

    在Spring框架中,事务管理是实现业务逻辑时不可或缺的一部分,它确保了数据的一致性和完整性。Spring提供了多种事务管理方式,其中基于注解的事务管理是近年来常用的模式,因为它简化了代码并提高了可读性。本文将...

    注解实现AOP通知

    2. 后置通知(@After):在目标方法执行后,无论其是否抛出异常都会执行。常用于清理工作,如关闭资源。`@After`注解的方法会在目标方法执行完毕后运行。 3. 返回后通知(@AfterReturning):在目标方法正常返回后执行...

Global site tag (gtag.js) - Google Analytics