Springboot中异步操作的最佳实践
写在前面
这里总结下 ,Springboot 中异步操作的最佳实践模板,仅供参考,解决包括异步操作中的事务、以及全局线程的监控
一、基本准备
-
1、springboot web 项目
-
2、异步线程配置,如下
1.1、如下,配置异步线程,以及相关线程池参数配置
/** * 异步配置 */
@Component
@EnableAsync
public class AsyncConfig {
/** * 异步日志 task * * @return */
@Bean("logTask")
public AsyncTaskExecutor getLogAsyncExecutor() {
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(100);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.setThreadNamePrefix("Async-logTask-");
executor.initialize();
return executor;
}
/** * 其他异步 task * * @return */
@Bean("otherTask")
public AsyncTaskExecutor getLogAsyncExecutor2() {
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(100);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.setThreadNamePrefix("Async-logTask-");
executor.initialize();
return executor;
}
// 其他自定义的 异步线程配置
}
1.2、线程监控配置
@Slf4j
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor{
/** * @Title: showThreadPoolInfo * @Description: 展示当前线程池任务:线程池-已提交任务-已完成任务-活跃线程-队列缓存数 * void * @throws */
private void showThreadPoolInfo(){
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
if(null==threadPoolExecutor){
return;
}
log.info("线程池监控>>>{}, taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo();
return super.submit(task);
}
@Override
public void execute(Runnable task) {
showThreadPoolInfo();
super.execute(task);
}
}
二、使用方式
2.1、定义 异步操作
定义为 Spring Bean
@Service
@Slf4j
@Async("logTask") // 这里如果找不到 Bean,会同步操作
public class LogService {
@Autowired
private ConfigurationChangeLogRepository logRepository;
/** * @param info * CompletableFuture 也可承载对象,用于某些场景中异步回执检查机制 */
public CompletableFuture accessorAdd(OperationSystemInfo info) {
final String currentUser = SecurityUtils.getCurrentUserName();
final LocalDateTime now = LocalDateTime.now();
log.info("接入方创建日志写入...");
ConfigurationChangeLog log = new ConfigurationChangeLog();
log.setChangeUser(currentUser);
log.setChangeDate(now);
log.setChangeType(LogEnum.ADD.name());
log.setChangeInfo(OperateModule.ACCESSOR.getText());
log.setChangeDetail(JSONUtils.obj2json(info));
logRepository.save(log);
return CompletableFuture.completedFuture(null);
}
}
2.2、调用异步操作
可以在任何操作中 ,注入 异步Bean操作,如下
@Resource
private LogService logService;
@Override
@Transactional
public void save(OperationSystemAddRequest dto) {
OperationSystemInfo info = operateStatemMapper.toEntity(dto);
this.verifyAddIfDuplicate(dto);
LocalDateTime now = LocalDateTime.now();
String currentUserName = SecurityUtils.getCurrentUserName();
// 基础数据封装
info.setStatus(SystemEnum.SystemStatus.ENABLE.getKey());
info.setCreateDate(now);
info.setLastModifuDate(now);
info.setCreateUser(currentUserName);
info.setLastModifyUser(currentUserName);
OperationSystemInfo save = accessorManageDao.save(info);
// 这里的 join 操作,将异步中的回调信息,合并到 主线程中,解决了异步操作中的事务问题
CompletableFuture completableFuture = logService.accessorAdd(save);
completableFuture.join();
}