Springboot MDC traceId日志中打印唯一traceId

参考: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);
    }

结果
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值