当前位置: 首页 > news >正文

聊聊LogbackMDCAdapter

本文主要研究一下LogbackMDCAdapter

MDCAdapter

org/slf4j/spi/MDCAdapter.java

public interface MDCAdapter {/*** Put a context value (the <code>val</code> parameter) as identified with* the <code>key</code> parameter into the current thread's context map. * The <code>key</code> parameter cannot be null. The <code>val</code> parameter* can be null only if the underlying implementation supports it.* * <p>If the current thread does not have a context map it is created as a side* effect of this call.*/public void put(String key, String val);/*** Get the context identified by the <code>key</code> parameter.* The <code>key</code> parameter cannot be null.* * @return the string value identified by the <code>key</code> parameter.*/public String get(String key);/*** Remove the context identified by the <code>key</code> parameter.* The <code>key</code> parameter cannot be null. * * <p>* This method does nothing if there is no previous value * associated with <code>key</code>.*/public void remove(String key);/*** Clear all entries in the MDC.*/public void clear();/*** Return a copy of the current thread's context map, with keys and * values of type String. Returned value may be null.* * @return A copy of the current thread's context map. May be null.* @since 1.5.1*/public Map<String, String> getCopyOfContextMap();/*** Set the current thread's context map by first clearing any existing * map and then copying the map passed as parameter. The context map * parameter must only contain keys and values of type String.* * Implementations must support null valued map passed as parameter.* * @param contextMap must contain only keys and values of type String* * @since 1.5.1*/public void setContextMap(Map<String, String> contextMap);/*** Push a value into the deque(stack) referenced by 'key'.*      * @param key identifies the appropriate stack* @param value the value to push into the stack* @since 2.0.0*/public void pushByKey(String key, String value);/*** Pop the stack referenced by 'key' and return the value possibly null.* * @param key identifies the deque(stack)* @return the value just popped. May be null/* @since 2.0.0*/public String popByKey(String key);/*** Returns a copy of the deque(stack) referenced by 'key'. May be null.* * @param key identifies the  stack* @return copy of stack referenced by 'key'. May be null.* * @since 2.0.0*/public Deque<String>  getCopyOfDequeByKey(String key);/*** Clear the deque(stack) referenced by 'key'. * * @param key identifies the  stack* * @since 2.0.0*/public void clearDequeByKey(String key);}

slf4j定义了MDCAdapter接口,该接口定义了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法

LogbackMDCAdapter

ch/qos/logback/classic/util/LogbackMDCAdapter.java

public class LogbackMDCAdapter implements MDCAdapter  {// BEWARE: Keys or values placed in a ThreadLocal should not be of a type/class// not included in the JDK. See also https://jira.qos.ch/browse/LOGBACK-450final ThreadLocal<Map<String, String>> readWriteThreadLocalMap = new ThreadLocal<Map<String, String>>();final ThreadLocal<Map<String, String>> readOnlyThreadLocalMap = new ThreadLocal<Map<String, String>>();private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();//......}      

LogbackMDCAdapter实现了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques来实现

readWriteThreadLocalMap

    public void put(String key, String val) throws IllegalArgumentException {if (key == null) {throw new IllegalArgumentException("key cannot be null");}Map<String, String> current = readWriteThreadLocalMap.get();if (current == null) {current = new HashMap<String, String>();readWriteThreadLocalMap.set(current);}current.put(key, val);nullifyReadOnlyThreadLocalMap();}@Overridepublic String get(String key) {Map<String, String> hashMap = readWriteThreadLocalMap.get();if ((hashMap != null) && (key != null)) {return hashMap.get(key);} else {return null;}}@Overridepublic void remove(String key) {if (key == null) {return;}Map<String, String> current = readWriteThreadLocalMap.get();if (current != null) {current.remove(key);nullifyReadOnlyThreadLocalMap();}}@Overridepublic void clear() {readWriteThreadLocalMap.set(null);nullifyReadOnlyThreadLocalMap();}private void nullifyReadOnlyThreadLocalMap() {readOnlyThreadLocalMap.set(null);}  public void setContextMap(Map contextMap) {if (contextMap != null) {readWriteThreadLocalMap.set(new HashMap<String, String>(contextMap));} else {readWriteThreadLocalMap.set(null);}nullifyReadOnlyThreadLocalMap();}      

put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,同时修改操作会同时调用nullifyReadOnlyThreadLocalMap,将readOnlyThreadLocalMap设置为null

getCopyOfContextMap

    public Map getCopyOfContextMap() {Map<String, String> readOnlyMap = getPropertyMap();if (readOnlyMap == null) {return null;} else {return new HashMap<String, String>(readOnlyMap);}}public Map<String, String> getPropertyMap() {Map<String, String> readOnlyMap = readOnlyThreadLocalMap.get();if (readOnlyMap == null) {Map<String, String> current = readWriteThreadLocalMap.get();if (current != null) {final Map<String, String> tempMap = new HashMap<String, String>(current);readOnlyMap = Collections.unmodifiableMap(tempMap);readOnlyThreadLocalMap.set(readOnlyMap);}}return readOnlyMap;}    

getCopyOfContextMap方法通过getPropertyMap获取,如果不为null则新创建HashMap返回;getPropertyMap先从readOnlyThreadLocalMap读取,如果readOnlyThreadLocalMap为null则从readWriteThreadLocalMap拷贝一份unmodifiableMap,并设置到readOnlyThreadLocalMap

threadLocalMapOfDeques

    @Overridepublic void pushByKey(String key, String value) {threadLocalMapOfDeques.pushByKey(key, value);}@Overridepublic String popByKey(String key) {return threadLocalMapOfDeques.popByKey(key);}@Overridepublic Deque<String> getCopyOfDequeByKey(String key) {return threadLocalMapOfDeques.getCopyOfDequeByKey(key);}@Overridepublic void clearDequeByKey(String key) {threadLocalMapOfDeques.clearDequeByKey(key);}

pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques,它是ThreadLocalMapOfStacks类型

ThreadLocalMapOfStacks

org/slf4j/helpers/ThreadLocalMapOfStacks.java

public class ThreadLocalMapOfStacks {// BEWARE: Keys or values placed in a ThreadLocal should not be of a type/class// not included in the JDK. See also https://jira.qos.ch/browse/LOGBACK-450final ThreadLocal<Map<String, Deque<String>>> tlMapOfStacks = new ThreadLocal<>();public void pushByKey(String key, String value) {if (key == null)return;Map<String, Deque<String>> map = tlMapOfStacks.get();if (map == null) {map = new HashMap<>();tlMapOfStacks.set(map);}Deque<String> deque = map.get(key);if (deque == null) {deque = new ArrayDeque<>();}deque.push(value);map.put(key, deque);}public String popByKey(String key) {if (key == null)return null;Map<String, Deque<String>> map = tlMapOfStacks.get();if (map == null)return null;Deque<String> deque = map.get(key);if (deque == null)return null;return deque.pop();}public Deque<String> getCopyOfDequeByKey(String key) {if (key == null)return null;Map<String, Deque<String>> map = tlMapOfStacks.get();if (map == null)return null;Deque<String> deque = map.get(key);if (deque == null)return null;return new ArrayDeque<String>(deque);}/*** Clear the deque(stack) referenced by 'key'. * * @param key identifies the  stack* * @since 2.0.0*/public void clearDequeByKey(String key) {if (key == null)return;Map<String, Deque<String>> map = tlMapOfStacks.get();if (map == null)return;Deque<String> deque = map.get(key);if (deque == null)return;deque.clear();}}

ThreadLocalMapOfStacks是slf4j定义的,基于ThreadLocal<Map<String, Deque<String>>>实现的

小结

slf4j定义了MDCAdapter接口,该接口定义了put、get、remove、clear、getCopyOfContextMap、setContextMap、pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey方法;LogbackMDCAdapter实现了MDCAdapter接口,它基于readWriteThreadLocalMap、readOnlyThreadLocalMap、threadLocalMapOfDeques来实现,其中put、get、remove、clear、setContextMap都是基于readWriteThreadLocalMap,pushByKey、popByKey、getCopyOfDequeByKey、clearDequeByKey均是基于threadLocalMapOfDeques。

http://www.lryc.cn/news/227189.html

相关文章:

  • spring命名空间注入和XML自动装配、引入外部配置文件
  • 【2024年11月份--2024精灵云校招C++笔试题】
  • Visual Studio 2019下编译OpenCV 4.7 与OpenCV 4.7 contrib
  • 【Linux网络】系统调优之聚合链路bonding,可以实现高可用和负载均衡
  • k8s持久化存储PV、PVC
  • CocosCreator3.8原生引擎源码研究
  • 高二英语上
  • JavaWeb Day10 案例 准备工作
  • Nginx:不同域名访问同一台机器的不同项目
  • C++(20):new数组时元素个数自动推到
  • 使用visualStudio发布可执行文件
  • yolo系列报错(持续补充ing)
  • Technology Strategy Patterns 学习笔记9 - bringing it all together
  • Redis(12)| 过期删除策略和内存淘汰策略
  • Go-服务注册和发现,负载均衡,配置中心
  • k8s-实验部署 1
  • Git的原理与使用(一)
  • 1204. 错误票据
  • uniapp中在组件中使用被遮挡或层级显示问题
  • windows下安装es及logstash、kibna
  • 华为ensp:rip宣告
  • Django中简单的增删改查
  • HCIE-Rainbow迁移工具
  • AI 绘画 | Stable Diffusion 涂鸦功能与局部重绘
  • [LeetCode周赛复盘] 第 371 场周赛20231112
  • Google Guava Cache LoadingCache 基本使用
  • AWS云服务器EC2实例进行操作系统迁移
  • 《015.SpringBoot+vue之音乐网》【前后端分离】
  • 网格算法和穷举法
  • 【AI】自回归 (AR) 模型使预测和深度学习变得简单