参考:https://mp.weixin.qq.com/s/3VmgxcoFazMMhnzU8ddnKQ
代码线程池配置
@EnableAsync
@Configuration
public class ThreadPoolConfig {
/**
* IO密集型任务 = 一般为2*CPU核心数(常出现于线程中:数据库数据交互、文件上传下载、网络数据传输等等)
* CPU密集型任务 = 一般为CPU核心数+1(常出现于线程中:复杂算法)
* 混合型任务 = 视机器配置和复杂度自测而定
*/
@Bean(name = "asyncTaskExecutor")
public ThreadPoolTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//1: 核心线程数目
executor.setCorePoolSize(5);
//2: 指定最大线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(10);
//3: 队列中最大的数目
executor.setQueueCapacity(200);
//4: 线程名称前缀
executor.setThreadNamePrefix("kap-Thread-");
//5:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy: 会在execute 方法的调用线程中运行被拒绝的任务,如果执行程序已关闭,则会丢弃该任务
// AbortPolicy: 抛出java.util.concurrent.RejectedExecutionException异常
// DiscardOldestPolicy: 抛弃旧的任务
// DiscardPolicy: 抛弃当前的任务
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//6: 线程空闲后的最大存活时间(默认值 60),当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//7:线程空闲时间,当线程空闲时间达到keepAliveSeconds(秒)时,线程会退出,直到线程数量等于corePoolSize,如果allowCoreThreadTimeout=true,则会直到线程数量等于0
executor.setAllowCoreThreadTimeOut(false);
// 8.设置线程traceId
executor.setTaskDecorator(new MdcTaskDecorator());
//
executor.initialize();
return executor;
}
}
异步调用线程设置traceId
public class MdcTaskDecorator implements TaskDecorator{
/**
* 使异步线程池获得主线程的上下文
* @param runnable
* @return
*/
@Override
public Runnable decorate(Runnable runnable) {
Map<String,String> map = MDC.getCopyOfContextMap();
return () -> {
try{
MDC.setContextMap(map);
runnable.run();
} finally {
MDC.clear();
}
};
}
}
返回对象设置traceId
@Data
@ApiModel(value = "接口返回对象", description = "接口返回对象")
public class Result<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 日志跟踪标识
*/
private static final String TRACE_ID = "TRACE_ID";
/**
* 成功标志
*/
@ApiModelProperty(value = "成功标志")
private boolean success = true;
/**
* 返回处理消息
*/
@ApiModelProperty(value = "返回处理消息")
private String message = "操作成功!";
/**
* 返回代码
*/
@ApiModelProperty(value = "返回代码")
private Integer code = 0;
/**
* 返回数据对象 data
*/
@ApiModelProperty(value = "返回数据对象")
private T result;
private String traceId;
/**
* 时间戳
*/
@ApiModelProperty(value = "时间戳")
private long timestamp = System.currentTimeMillis();
public Result() {
this.traceId = MDC.get(TRACE_ID);
}
public static <T> Result<T> OK() {
Result<T> result = new Result<T>();
result.setSuccess(true);
result.setCode(1);
result.setMessage("成功");
result.traceId = MDC.get(TRACE_ID);
return result ;
}
}
日志配置添加traceId
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - [%X{TRACE_ID}] - %msg%n</pattern>
测试案例采用shiro做安全框架
在shiro的filter添加traceId
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {
/**
* 日志跟踪标识
*/
private static final String TRACE_ID = "TRACE_ID";
/**
*
*/
@Override
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader("access-token");
JwtToken jwtToken = new JwtToken(token);
// 提交给realm进行登录验证,如果错误会抛出异常并被捕获
getSubject(request, response).login(jwtToken);
//添加TRACE_ID
MDC.put(TRACE_ID, UUID.randomUUID().toString());
return true;
}
@Override
public void destroy() {
MDC.clear();
}
}
测试
@GetMapping("/getLeaderUserLists")
@ApiOperation(value = "查询领导人员列表", notes = "查询领导人员列表")
public Result<?> getLeaderUserList() {
QueryWrapper<UserInfoView> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(UserInfoView::getUserIdentity, 2);
List<UserInfoView> list = userInfoViewService.list(queryWrapper);
//异步调用
CompletableFuture<Void> future =
CompletableFuture.runAsync(() -> {
sysUserService.getUserListLikeUserNameVoid("XX");
},executor);
return Result.OK(list);
}
结果