Spring支持的消费器模式,支持在当前事务提交、或回滚的前、后执行业务操作

关键补充

1. 注册同步器的核心类:TransactionSynchronizationManager

TransactionSynchronizationManager.registerSynchronization(...) 是将自定义的 TransactionSynchronization 实现类注册到当前事务上下文的核心方法,只有在活跃的事务中 (即 TransactionSynchronizationManager.isSynchronizationActive() 返回 true)注册才有效。

2. afterCommit 的特性
  • 执行时机:事务提交成功后异步执行(但仍在当前线程),不会阻塞主事务流程;
  • 异常处理:afterCommit 中抛出的异常不会回滚已提交的事务 (事务已完成),因此必须自行捕获异常(如你的代码中加了 try-catch);
  • 适用场景:适合执行事务提交后才允许的操作(如发送消息、更新缓存、调用外部接口等)。

四、完整继承 / 实现关系

plaintext

复制代码
java.lang.Object
  ↳ 自定义匿名内部类
      ↳ 实现 org.springframework.transaction.support.TransactionSynchronization 接口
          ↳ 重写接口中的 afterCommit() 方法

总结

afterCommit 是 Spring 框架 TransactionSynchronization 接口的标准回调方法,用于定义事务提交后的自定义逻辑;你的代码通过实现该接口并重写 afterCommit,实现了 "事务提交后执行指定消费逻辑" 的核心功能。

工具类实现

java 复制代码
package com.yonyoucloud.fi.tlm.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.imeta.orm.base.BizObject;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;

@Slf4j
public class FmTransactionUtil {

    /**
     * 单消费器:事务成功提交后执行(仅在事务提交成功时触发,回滚 / 超时不会执行)
     *
     * @param bill 业务单据范型
     * @param consumer
     * @param <T>
     */
    public static <T extends BizObject> void doAfterTransactionCommit(T bill, Consumer<T> consumer) {
        if (consumer == null) {
            return;
        }
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                safeAccept(consumer, bill);
            }
        });
    }


    /**
     * 多消费器:事务成功提交后执行(仅在事务提交成功时触发,回滚 / 超时不会执行)
     *
     * @param bill 业务单据范型
     * @param consumerList
     * @param <T>
     */
    public static <T extends BizObject> void doAfterTransactionCommit(T bill, List<Consumer<T>> consumerList) {
        if (CollectionUtils.size(consumerList) == 0) {
            return;
        }
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                for (Consumer<T> consumer : consumerList) {
                    safeAccept(consumer, bill);
                }
            }
        });
    }

    /**
     * 单消费器:事务完成后执行(无论提交/回滚,都会执行)
     *
     * @param bill 业务单据范型
     * @param consumer
     * @param <T>
     */
    public static <T extends BizObject> void doAfterTransactionCompletion(T bill, Consumer<T> consumer) {
        if (consumer == null) {
            return;
        }
        doAfterTransactionCompletion(bill, Collections.singletonList(consumer));
    }

    /**
     * 多消费器:事务完成后执行(无论提交/回滚,都会执行)
     *
     * @param bill 业务单据范型
     * @param consumerList
     * @param <T>
     */
    public static <T extends BizObject> void doAfterTransactionCompletion(T bill, List<Consumer<T>> consumerList) {
        if (CollectionUtils.isEmpty(consumerList)) {
            return;
        }
        // 先校验是否在活跃事务中,避免非事务场景报错
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            log.warn("当前无活跃事务,直接执行消费逻辑");
            // 非事务场景下直接执行(可选,根据业务决定)
            consumerList.forEach(consumer -> safeAccept(consumer, bill));
            return;
        }

        // 注册事务同步器,重写 afterCompletion 方法
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCompletion(int status) {
                // status 枚举值:区分事务最终状态
                // 遍历执行所有消费器,单个消费器异常不影响其他
                consumerList.forEach(consumer -> safeAccept(consumer, bill));
            }
        });
    }

    // 封装安全执行逻辑,避免单个消费器异常扩散
    private static <T extends BizObject> void safeAccept(Consumer<T> consumer, T bill) {
        try {
            consumer.accept(bill);
        } catch (Exception e) {
            log.error("事务完成后执行消费逻辑失败", e);
        }
    }

}

代码使用示范

update是业务对象,customer是约定的消费器变量名称。这么写就行

java 复制代码
try {

} catch (Exception e) {

} finally {
            // 生单无论成功或失败,即事务提交或回滚,都需要回写失败原因。update是业务对象
            FmTransactionUtil.doAfterTransactionCompletion(update, customer ->
                    AppContext.getBean(FrTransactionCompletionService.class).writeBackFRAutoInfuseFailReason(update));
}    
相关推荐
老毛肚4 小时前
手写mybatis
java·数据库·mybatis
两点王爷4 小时前
Java基础面试题——【Java语言特性】
java·开发语言
choke2334 小时前
[特殊字符] Python 文件与路径操作
java·前端·javascript
choke2334 小时前
Python 基础语法精讲:数据类型、运算符与输入输出
java·linux·服务器
岁岁种桃花儿4 小时前
CentOS7 彻底卸载所有JDK/JRE + 重新安装JDK8(实操完整版,解决kafka/jps报错)
java·开发语言·kafka
一灰灰blog4 小时前
Spring AI中的多轮对话艺术:让大模型主动提问获取明确需求
数据库·人工智能·spring
roman_日积跬步-终至千里5 小时前
【Java并发】Java 线程池实战:警惕使用CompletableFuture.supplyAsync
java·开发语言·网络
毕设源码-钟学长5 小时前
【开题答辩全过程】以 基于Springboot的扶贫众筹平台为例,包含答辩的问题和答案
java·spring boot·后端
lucky67075 小时前
Windows 上彻底卸载 Node.js
windows·node.js
CodeSheep程序羊5 小时前
拼多多春节加班工资曝光,没几个敢给这个数的。
java·c语言·开发语言·c++·python·程序人生·职场和发展