项目中有一个功能涉及多个业务流程,且在同一个事务中,每个业务流程结束后都需要进行RPC调用,考虑到RPC调用的代价,决定做成异步调用,但是由于每个调用都必须在业务流程结束后进行,这时候就想到TransactionSynchronizationManager和TransactionSynchronizationAdapter。
TransactionSynchronizationManager这个类中由一系列的ThreadLocal ,我们需要关注的是synchronizations,在后面使用到的TransactionSynchronizationManager.isSynchronizationActive()、TransactionSynchronizationManager.registerSynchronization()和new TransactionSynchronizationAdapter(),都与它密切有关。
在Spring在开启数据库事务(无论是使用@Transactional注解,还是用xml配置)时,都会向其中写入一个实例,用于自动处理Connection的获取、提交或回滚等操作。
再看isSynchronizationActive()方法,判断了synchronizations中是否有数据(Set<TransactionSynchronization>非null即可,并不要求其中有TransactionSynchronization实例。
再看registerSynchronization()方法,首先调用isSynchronizationActive()做一个校验;然后将入参synchronization添加到synchronizations 中。入参synchronization中的方法不会在这里执行,而是要等到事务执行到特定阶段时才会被调用。
TransactionSynchronizationAdapter是一个适配器:它实现了TransactionSynchronization接口,并为每一个接口方法提供了一个空的实现。这类适配器的基本思想是:接口中定义了很多方法,然而业务代码往往只需要实现其中一小部分。利用这种“空实现”适配器,我们可以专注于业务上需要处理的回调方法,而不用在业务类中放大量而且重复的空方法。
结合TransactionSynchronizationManager和TransactionSynchronizationAdapter利用ThreadPoolExecutor实现一个事务后多线程处理功能。
package com.*.module.spring.support; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.support.TransactionSynchronizationAdapter; import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; /** * 事务提交异步线程 * * @author ly */ public class TransactionAfterCommitExecutor extends ThreadPoolExecutor { private static final Logger LOGGER = LoggerFactory.getLogger(TransactionAfterCommitExecutor.class); public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); } public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); } public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); } public TransactionAfterCommitExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } private ThreadLocal<List<Runnable>> currentRunables = new ThreadLocal<List<Runnable>>(){ @Override protected List<Runnable> initialValue() { return new ArrayList<>(5); } }; private ThreadLocal<Boolean> registed = new ThreadLocal<Boolean>(){ @Override protected Boolean initialValue() { return false; } }; /** * 默认策略丢弃最老的数据 */ public TransactionAfterCommitExecutor() { this( 50, 500, 500L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), new ThreadFactoryBuilder().setNameFormat("transaction-after-commit-call-pool-%d").build(), new ThreadPoolExecutor.DiscardOldestPolicy()); } @Override public void execute(final Runnable runnable) { //如果事务同步未启用则认为事务已经提交,马上进行异步处理 if (!TransactionSynchronizationManager.isSynchronizationActive()) { super.execute(runnable); } else { //同一个事务的合并到一起处理 currentRunables.get().add(runnable); //如果存在事务则在事务结束后异步处理 if(!registed.get()){ TransactionSynchronizationManager.registerSynchronization(new AfterCommitTransactionSynchronizationAdapter()); registed.set(true); } } } @Override public Future<?> submit(final Runnable runnable) { //如果事务同步未启用则认为事务已经提交,马上进行异步处理 if (!TransactionSynchronizationManager.isSynchronizationActive()) { return super.submit(runnable); } else { final RunnableFuture<Void> ftask = newTaskFor(runnable, null); //如果存在事务则在事务结束后异步处理 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { TransactionAfterCommitExecutor.super.submit(ftask); } }); return ftask; } } private class AfterCommitTransactionSynchronizationAdapter extends TransactionSynchronizationAdapter{ @Override public void afterCompletion(int status) { final List<Runnable> txRunables = new ArrayList<>(currentRunables.get()); currentRunables.remove(); registed.remove(); if(status == STATUS_COMMITTED){ TransactionAfterCommitExecutor.super.execute(new Runnable() { @Override public void run() { for (Runnable runnable : txRunables) { try { runnable.run(); } catch (Exception e) { LOGGER.error("ex:",e); } } } }); } } } }