Mdc多线程传递链路id传递配置

项目中在多线程使用的地方,日志里的链路id(mdc类设置的)没法自动往子线程传递,需要手动设置进去
目前配置只支持spring提供的线程池ThreadPoolTaskExecutor使用
这边通过spring提供的装饰器拓展接口,将该类设置进去

public void setTaskDecorator(TaskDecorator taskDecorator) {
		this.taskDecorator = taskDecorator;
	}
/**
 * @author :wangcheng
 * @date2021/12/6
 **/
@Component
public class MDCTaskDecorator implements TaskDecorator, BeanPostProcessor {

    @Override
    public Runnable decorate(Runnable runnable) {
        Map<String, String> mdcContext = MDC.getCopyOfContextMap();
        return () -> {
            try {
                if (mdcContext!=null) {
                    MDC.setContextMap(mdcContext);
                }
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ThreadPoolTaskExecutor) {
            ((ThreadPoolTaskExecutor) bean).setTaskDecorator(this);
        }
        return bean;
    }

}

有的老版本spring线程池没有提供该拓展接口,就要手动在包一层了

threadPoolTaskExecutor.execute(mdcTaskDecorator.decorate(()->xxxxx具体执行));

至于为什么子线程内部通过mdc.get(“xx”)方法获取不到值,可以进入源码看看
项目中使用logback日志,通过断点进入该put方法

public static void put(String key, String val) throws IllegalArgumentException {
        if (key == null) {
            throw new IllegalArgumentException("key parameter cannot be null");
        }
        if (mdcAdapter == null) {
            throw new IllegalStateException("MDCAdapter cannot be null. See also " + NULL_MDCA_URL);
        }
        mdcAdapter.put(key, val);
    }

通过适配器 static MDCAdapter mdcAdapter;进入put方法

public interface MDCAdapter {


    public void put(String key, String val);

    public String get(String key);


    public void remove(String key);

 
    public void clear();


    public Map<String, String> getCopyOfContextMap();

 
    public void setContextMap(Map<String, String> contextMap);
}

最终来到LogbackMDCAdapter

public class LogbackMDCAdapter implements MDCAdapter {

//省略其他。。。


final ThreadLocal<Map<String, String>> copyOnThreadLocal = new ThreadLocal<Map<String, String>>();

public void put(String key, String val) throws IllegalArgumentException {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }

        Map<String, String> oldMap = copyOnThreadLocal.get();
        Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);

        if (wasLastOpReadOrNull(lastOp) || oldMap == null) {
            Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);
            newMap.put(key, val);
        } else {
            oldMap.put(key, val);
        }
    }

}

可以看到最终put的是这个copyOnThreadLocal,无法多线程共享

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值