需要在事务提交后执行的操作-springBoot版。
需要在事务提交后执行的操作-springBoot版。
应用场景, 注册成功后需要将发送 短信、邮件 将用户推送至不同平台
import com.example.springbootevent.factory.TransactionThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @author: Zoudx
* @Date: 2022/7/18 16:05
* @Description: 事务结束后需执行操作
*/
@Component
public class TransactionAfterCommitExecutor implements Executor, TransactionSynchronization {
private static final Logger logger = LoggerFactory.getLogger(TransactionAfterCommitExecutor.class);
private static final ThreadLocal<List<Runnable>> RUNNABLES = new ThreadLocal<>();
private final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100), new TransactionThreadFactory("TransactionAfterCommitExecutor"), new ThreadPoolExecutor.AbortPolicy());
@Override
public void execute(Runnable runnable) {
logger.info("{}:Execute after transaction ends" , Thread.currentThread().getName());
// 不存在事务, 直接执行
if (!TransactionSynchronizationManager.isActualTransactionActive()) {
runnable.run();
return;
}
// 存在事务,存入线程变量中, 待事务提交后执行
List<Runnable> runnables = RUNNABLES.get();
if (runnables == null) {
runnables = new ArrayList<>();
}
TransactionSynchronizationManager.registerSynchronization(this);
runnables.add(runnable);
RUNNABLES.set(runnables);
}
@Override
public void afterCommit() {
// 事务结束后执行
List<Runnable> runnables = RUNNABLES.get();
for (Runnable runnable : runnables) {
logger.info("execute runnable");
try {
THREAD_POOL_EXECUTOR.execute(runnable);
} catch (Exception e) {
logger.error("Failed to execute runnable:{}", runnable);
}
}
}
@Override
public void afterCompletion(int status) {
logger.info("Transaction completed with status {}", status == STATUS_COMMITTED ? "COMMITTED" : "ROLLED_BACK");
RUNNABLES.remove();
}
}
TransactionThreadFactory
/**
* @author: Zoudx
* @Date: 2022/7/19 10:05
* @Description:
*/
public class TransactionThreadFactory implements ThreadFactory {
private static final Logger logger = LoggerFactory.getLogger(TransactionAfterCommitExecutor.class);
/**
* 线程编号
*/
private final AtomicInteger count = new AtomicInteger(0);
/**
* 线程前缀
*/
private String threadPre;
public TransactionThreadFactory(String threadName) {
this.threadPre = threadName;
}
@Override
public Thread newThread(Runnable r) {
int increment = count.getAndIncrement();
Thread t = new Thread(r);
t.setName(threadPre + "-" + increment);
logger.info("create {} thread", increment);
return t;
}
}
Service
/**
* @author: Zoudx
* @Date: 2022/7/15 11:40
* @Description: 用户业务处理类
*/
@Service
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
private final TransactionAfterCommitExecutor afterCommitExecutor;
@Override
@Transactional(rollbackFor = Exception.class)
public void register(User user) {
// 注册
logger.info("用户注册,参数正常:{}", JSON.toJSON(user));
try {
// 保存用户
this.save(user);
// 注册结束后需要处理操作
afterCommitExecutor.execute(() -> ApplicationContextUtil.publishEvent(new UserEvent(user, user.getId())));
} catch (Exception e) {
logger.error("Create user Failed");
}
}
}
ApplicationContextUtil用户获取容器中的bean以及发布事件
/**
* @author: Zoudx
* @Date: 2022/7/15 11:42
* @Description:
*/
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextUtil.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
public static <T> T getBean(String beanName) {
return (T) applicationContext.getBean(beanName);
}
public static void publishEvent(Object object) {
applicationContext.publishEvent(object);
}
}