MDC (Mapped Diagnostic Context)
MDC
是org.slf4j
包下的一个类,它的全称是Mapped Diagnostic Context,我们可以认为它是一个线程安全的存放诊断日志的容器。
MDC的底层是用了ThreadLocal
来保存数据的。
我们可以用它传递参数。
例如现在有这样一种场景:我们使用RestTemplate
调用远程接口时,有时需要在header
中传递信息,比如:traceId,source等,便于在查询日志时能够串联一次完整的请求链路,快速定位问题。
这种业务场景就能通过ClientHttpRequestInterceptor
接口实现,具体做法如下:
第一步,定义一个LogFilter拦截所有接口请求,在MDC中设置traceId:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class LogFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { MdcUtil.add(UUID.randomUUID().toString()); System.out.println( "记录请求日志" ); chain.doFilter(request, response); System.out.println( "记录响应日志" ); } @Override public void destroy() { } } |
第二步,实现ClientHttpRequestInterceptor
接口,MDC中获取当前请求的traceId,然后设置到header中:
1 2 3 4 5 6 7 8 | public class RestTemplateInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte [] body, ClientHttpRequestExecution execution) throws IOException { request.getHeaders().set( "traceId" , MdcUtil.get()); return execution.execute(request, body); } } |
第三步,定义配置类,配置上面定义的RestTemplateInterceptor
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @Configuration public class RestTemplateConfiguration { @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setInterceptors(Collections.singletonList(restTemplateInterceptor())); return restTemplate; } @Bean public RestTemplateInterceptor restTemplateInterceptor() { return new RestTemplateInterceptor(); } } |
其中MdcUtil其实是利用MDC工具在ThreadLocal中存储和获取traceId
1 2 3 4 5 6 7 8 9 10 11 12 | public class MdcUtil { private static final String TRACE_ID = "TRACE_ID" ; public static String get() { return MDC.get(TRACE_ID); } public static void add(String value) { MDC.put(TRACE_ID, value); } } |
在filter中执行接口方法之前,生成traceId,调用MdcUtil类的add方法添加到MDC中,然后在同一个请求的其他地方就能通过MdcUtil类的get方法获取到该traceId。
能使用MDC保存traceId等参数的根本原因是,用户请求到应用服务器,Tomcat会从线程池中分配一个线程去处理该请求。
那么该请求的整个过程中,保存到MDC的ThreadLocal中的参数,也是该线程独享的,所以不会有线程安全问题。
分类:
JAVA
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2017-10-09 list根据某个字段去重