使用场景
在链路追踪中,开启多线程后。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();
}
}