添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

MDC是什么?用法、源码一锅端

近期用到阿里的一款开源的数据同步工具 Canal,不经意之中看到了 MDC 的用法,而且平时项目中也多次用到 MDC,趁机科普一把。

通过今天的分享,能让你轻松 get 如下几点,绝对收获满满。

a)MDC 快速入门;

b)MDC 源码解读;

c)MDC 能干什么?

阿里开源项目 Canal:

老项目这么用过:

但是无论怎么用,都逃不过 MDC API 的使用,下面先花一分钟快速入门,然后再逐步去深入 MDC。

1. MDC 快速入门

MDC 全称是 Mapped Diagnostic Context,可以粗略的理解成是一个线程安全的存放诊断日志的容器。

首先看看 MDC 基本的 API 的用法,能抛代码的就不多废话(根据 logback 官方案例改编)。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import java.util.UUID;
 * MDC快速入门示例
 * @author 程序要老王头
public class SimpleMDC {
    private static final Logger logger = LoggerFactory.getLogger(SimpleMDC.class);
    public static final String REQ_ID = "REQ_ID";
    public static void main(String[] args) {
        MDC.put(REQ_ID, UUID.randomUUID().toString());
        logger.info("开始调用服务A,进行业务处理");
        logger.info("业务处理完毕,可以释放空间了,避免内存泄露");
        MDC.remove(REQ_ID);
        logger.info("REQ_ID 还有吗?{}", MDC.get(REQ_ID) != null);

代码编写完,貌似只有 MDC.put(K,V) 、MDC.remove(K) 两句是陌生的,先不着急解释它,等案例跑完就懂了,咱们继续往下看。

接下来配置 logback.xml,通过 %X{REQ_ID} 来打印 REQ_ID 的信息,logback.xml 文件内容如下。

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>[%t] [%X{REQ_ID}] - %m%n</Pattern>
        </layout>
    </appender>
    <root level="debug">
        <appender-ref ref="CONSOLE"/>
    </root>
</configuration>

引入依赖包,让代码跑起来

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.7</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-access</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
</dependencies>

程序跑起来,输出截图如下。

根据输出结果分析,能够得到两条结论。

第一: 如图中红色圈住部分所示,当 logback 内置的日志字段不能满足业务需求时,便可以借助 MDC 机制,将业务上想要输出的信息,通过 logback 给打印出来;

第二: 如蓝色圈住部分所示,当调用 MDC.remove(Key) 后,便可将业务字段从 MDC 中删除,日志中就不再打印请求 ID 啦;

趁热打铁,我们迅速看看在多线程情况下,使用 MDC 会发生什么现象呢?

还是基于上面的代码,把代码段放到了线程体内,稍微进行改造了一下,代码如下。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import java.util.UUID;
 * MDC快速入门示例
 * @author 程序要老王头
public class SimpleMDC {
    public static void main(String[] args) {
        new BizHandle("F0000").start();
        new BizHandle("F9999").start();
class BizHandle extends Thread {
    private static final Logger logger = LoggerFactory.getLogger(SimpleMDC.class);
    public static final String REQ_ID = "REQ_ID";
    private String funCode;
    public BizHandle(String funCode) {
        this.funCode = funCode;
    @Override
    public void run() {
        MDC.put(REQ_ID, UUID.randomUUID().toString());
        logger.info("开始调用服务{},进行业务处理", funCode);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            logger.info(e.getMessage());