MDC
获取父线程MDC中的内容 Map<String, String> context = MDC.getCopyOfContextMap();
设置contentMap MDC.setContextMap(context);
清空MDC内容 `MDC.clear();
实现线程池传递MDC
*{@link ThreadPoolTaskExecutor}的一个简单替换,可以在每个任务之前设置子线程的MDC数据。
- 在记录日志的时候,一般情况下我们会使用MDC来存储每个线程的特有参数,如身份信息等,以便更好的查询日志。
- 但是Logback在最新的版本中因为性能问题,不会自动的将MDC的内存传给子线程。所以Logback建议在执行异步线程前
- 先通过MDC.getCopyOfContextMap()方法将MDC内存获取出来,再传给线程。
- 并在子线程的执行的最开始调用MDC.setContextMap(context)方法将父线程的MDC内容传给子线程。
- https://logback.qos.ch/manual/mdc.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39public class MdcThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
/**
* 所有线程都会委托给这个execute方法,在这个方法中我们把父线程的MDC内容赋值给子线程
* https://logback.qos.ch/manual/mdc.html#managedThreads
*
* @param runnable
*/
public void execute(Runnable runnable) {
// 获取父线程MDC中的内容,必须在run方法之前,否则等异步线程执行的时候有可能MDC里面的值已经被清空了,这个时候就会返回null
Map<String, String> context = MDC.getCopyOfContextMap();
super.execute(() -> run(runnable, context));
}
/**
* 子线程委托的执行方法
*
* @param runnable {@link Runnable}
* @param context 父线程MDC内容
*/
private void run(Runnable runnable, Map<String, String> context) {
// 将父线程的MDC内容传给子线程
if (context != null) {
try {
MDC.setContextMap(context);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
try {
// 执行异步操作
runnable.run();
} finally {
// 清空MDC内容
MDC.clear();
}
}
}