Springboot中異步操作的最佳實踐
- 寫在前面
- 一、基本準備
- 1.1、如下,配置異步線程,以及相關線程池參數配置
- 1.2、線程監控配置
- 二、使用方式
- 2.1、定義 異步操作
- 2.2、調用異步操作
寫在前面
這裡總結下 ,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、定義 異步操作
@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、調用異步操作
@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();
}