多线程传递MDC值

1,414 阅读2分钟

使用场景

在链路追踪中,开启多线程后。logback日志中的MDC值就会丢失,该方法可以对MDC值父子线程直接相互传递。

MDC工具类


/**
 * 链路追踪工具类
 *
 * @author 苦瓜不苦
 * @date 2022/6/30 20:55
 **/
@Slf4j
public class MdcUtil {

    /**
     * 链路追踪KEY值
     */
    public final static String TRACE_ID = "traceId";

    /**
     * 服务器ID
     */
    private static String SERVER_ID;

    /**
     * 获取服务器ID标识
     *
     * @return
     */
    public static String getServerId() {
        if (Objects.isNull(SERVER_ID)) {
            try {
                String hostAddress = InetAddress.getLocalHost().getHostAddress();
                hostAddress = hostAddress.replace(".", "");
                SERVER_ID = Base64.encode(hostAddress);
            } catch (UnknownHostException e) {
                log.error("\n", e);
            }
        }
        return SERVER_ID;
    }


    /**
     * 设置全局唯一ID
     *
     * @param value ID值
     */
    public static void set(String value) {
        MDC.put(TRACE_ID, Objects.nonNull(value) ? value : UUID.randomUUID().toString().replace("-", ""));
    }


    /**
     * 获取ID值
     *
     * @return
     */
    public static String get() {
        return MDC.get(TRACE_ID);
    }


    /**
     * 获取MDC上下文对象
     *
     * @return
     */
    public static Map<String, String> getMap() {
        return MDC.getCopyOfContextMap();
    }

    /**
     * 设置MDC上下文对象
     *
     * @param map 上下文对象
     */
    public static void setMap(Map<String, String> map) {
        if (Objects.nonNull(map)) {
            MDC.setContextMap(map);
        }
    }


    /**
     * 清空MDC
     */
    public static void clear() {
        MDC.clear();
    }


}


线程池


/**
 * @author 苦瓜不苦
 * @date 2023/1/6 9:57
 **/
@Slf4j
@Configuration
public class ThreadPoolTaskExecutorConfig extends ThreadPoolTaskExecutor {

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        Map<String, String> map = MdcUtil.getMap();
        return super.submit(() -> {
            try {
                MdcUtil.setMap(map);
                return task.call();
            } catch (Exception e) {
                log.error("\n", e);
                return null;
            } finally {
                MdcUtil.clear();
            }
        });

    }

    @Override
    public Future<?> submit(Runnable task) {
        Map<String, String> map = MdcUtil.getMap();
        return super.submit(() -> {
            try {
                MdcUtil.setMap(map);
                task.run();
            } catch (Exception e) {
                log.error("\n", e);
            } finally {
                MdcUtil.clear();
            }
        });
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        Map<String, String> map = MdcUtil.getMap();
        super.execute(() -> {
            try {
                MdcUtil.setMap(map);
                task.run();
            } catch (Exception e) {
                log.error("\n", e);
            } finally {
                MdcUtil.clear();
            }
        }, startTimeout);
    }

    @Override
    public void execute(Runnable task) {
        Map<String, String> map = MdcUtil.getMap();
        super.execute(() -> {
            try {
                MdcUtil.setMap(map);
                task.run();
            } catch (Exception e) {
                log.error("\n", e);
            } finally {
                MdcUtil.clear();
            }
        });
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        Map<String, String> map = MdcUtil.getMap();
        return super.submitListenable(() -> {
            try {
                MdcUtil.setMap(map);
                task.run();
            } catch (Exception e) {
                log.error("\n", e);
            } finally {
                MdcUtil.clear();
            }
        });
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        Map<String, String> map = MdcUtil.getMap();
        return super.submitListenable(() -> {
            try {
                MdcUtil.setMap(map);
                return task.call();
            } catch (Exception e) {
                log.error("\n", e);
                return null;
            } finally {
                MdcUtil.clear();
            }
        });
    }

}


线程工具类



/**
 * 线程池工具类
 *
 * @author 苦瓜不苦
 * @date 2022/11/4 9:25
 **/
public class ThreadPoolUtil {

    /**
     * 线程池初始化数量
     */
    private final static Integer CORE_POOL_SIZE = 10;
    /**
     * 线程池最大线程数
     */
    private final static Integer MAX_POOL_SIZE = 30;
    /**
     * 空闲线程等待时间
     */
    private final static Integer KEEP_ALIVE_TIME = 50;
    /**
     * 队列等待线程数量
     */
    private final static Integer CAPACITY = 100;
    /**
     * 线程名称
     */
    private final static String THREAD_NAME = "thread-pool-";
    /**
     * 创建线程
     */
    public static ThreadPoolTaskExecutor EXECUTOR;


    static {
        // 初始化线程池
        EXECUTOR = new ThreadPoolTaskExecutorConfig();
        EXECUTOR.setCorePoolSize(CORE_POOL_SIZE);
        EXECUTOR.setMaxPoolSize(MAX_POOL_SIZE);
        EXECUTOR.setKeepAliveSeconds(KEEP_ALIVE_TIME);
        EXECUTOR.setQueueCapacity(CAPACITY);
        EXECUTOR.setThreadNamePrefix(THREAD_NAME);
        EXECUTOR.initialize();
    }


    /**
     * 开启多线程
     *
     * @param runnable
     */
    public static void execute(Runnable runnable) {
        EXECUTOR.execute(runnable);
    }

    /**
     * 获取线程池空闲数量
     *
     * @return
     */
    public static Integer freeThreadNumber() {
        return MAX_POOL_SIZE - EXECUTOR.getActiveCount();
    }


}