当前位置: 首页 > 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。

相关文章:

聊聊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 cur…...

spring命名空间注入和XML自动装配、引入外部配置文件

Spring p命名空间注入util命名空间注入基于XML的自动装配根据名称自动装配 Spring引入外部属性配置文件 p命名空间注入 作用&#xff1a;简化配置。 使用p命名空间注入的前提条件包括两个&#xff1a; ● 第一&#xff1a;在XML头部信息中添加p命名空间的配置信息&#xff1a…...

【2024年11月份--2024精灵云校招C++笔试题】

​ 考试形式 笔试考了三道算法题&#xff0c;笔试形式为阅读题目&#xff0c;然后用中文给出算法思路&#xff0c;最后给出算法例程&#xff0c;分数各占一半&#xff0c;简单&#xff0c;中等&#xff0c;复杂各一道题。我看9月份有人也是考这3道题&#xff0c;一模一样。 第…...

Visual Studio 2019下编译OpenCV 4.7 与OpenCV 4.7 contrib

一、环境 使用的环境是Win10,Visual Studio 2019,Cmake3.28,cdua 11.7&#xff0c;cudnn 8.5,如果只是在CPU环境下使用&#xff0c;则不用安装CUDA。要使用GPU处理&#xff0c;安装好CUDA之后&#xff0c;要测试安装的CUDA是否能用。不能正常使用的话&#xff0c;添加一下系统…...

【Linux网络】系统调优之聚合链路bonding,可以实现高可用和负载均衡

一、什么是多网卡绑定 二、聚合链路的工作模式 三、实操创建bonding设备&#xff08;mode1&#xff09; 1、实验 2、配置文件解读 3、查看bonding状态,验证bonding的高可用效果 三、nmcli实现bonding 一、什么是多网卡绑定 将多块网卡绑定同一IP地址对外提供服务&#xf…...

k8s持久化存储PV、PVC

容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重启它&#xff0c;但是容器中的文件将丢失——容器以干净的状态&#xff08;镜像最初的状态&#xff09;重新启动。其次&a…...

CocosCreator3.8原生引擎源码研究

1. Cocos Creator引擎架构图 2. 原始引擎源码流程图 下图中包含Android native层引擎到js适配层的启动和主循环的启用流程和必要说明&#xff0c;本猿比较懒&#xff0c;暂时不细述了&#xff0c;各位看官直接看图吧&#xff0c;还在细化扩充&#xff0c;后续逐渐更新。。。 版…...

高二英语上

unit 1 1.yarn三种意思 1.码&#xff1b; 2.庭院&#xff0c;天井&#xff1b; 3.花园&#xff1b;down**down 在这里是介词,也可以作副词&#xff0c;与 down 相对的是 up。请比较下列两句: 1.Look! Hes driving down the street . 2.Look! Hes driving up the street .这两例…...

JavaWeb Day10 案例 准备工作

目录​​​​​​​ 一、需求说明 二、环境搭建 &#xff08;一&#xff09;数据库 &#xff08;二&#xff09;后端 ①controller层 1.DeptController.java 2.EmpController.java ②mapper层 1.DeptMapper.java 2.EmpMapper.java ③pojo层 1.Dept.java 2.Emp.jav…...

Nginx:不同域名访问同一台机器的不同项目

Nginx很简单就可以解决同一台机器同时跑两个或者多个项目&#xff0c;而且都通过域名从80端口走。 以Windows环境下nginx服务为例&#xff0c;配置文件nginx.conf中&#xff0c;http中加上 include /setup/nginx-1.20.1/conf/conf.d/*.conf;删除server部分&#xff0c;完整如…...

C++(20):new数组时元素个数自动推到

C20在new数组时可以根据初始化列表&#xff0c;自动推到元素个数&#xff1a; #include <iostream> using namespace std;int main() {int *pd new int[]{1,2,3,4};for(auto i 0; i < 4; i){cout<<pd[i]<<endl;}return 0; }运行程序输出&#xff1a; 1…...

使用visualStudio发布可执行文件

编译成功后会在程序项目的路径下创建一个debug文件夹和一个release文件夹 文件夹中的具体文件入下所示 生成32位的可执行文件 32位的可执行文件可以在64位的计算机中执行&#xff0c;而64位的操作系统程序只能在64位的计算机中执行安装运行库的安装包根据电脑的版本选择合适的…...

yolo系列报错(持续补充ing)

文章目录 export GIT_PYTHON_REFRESHquiet解决 没有pt权重文件解决 python文件路径报错解决 读取文件列名报错解决 导入不同文件夹出错解决 megengine没有安装解决然后你发现它竟然还没有用 export GIT_PYTHON_REFRESHquiet 设置环境变量 GIT_PYTHON_REFRESH &#xff0c;这个…...

Technology Strategy Patterns 学习笔记9 - bringing it all together

1 Patterns Map 2 Creating the Strategy 2.1 Ansoff Growth Matrix 和owth-share Matrix 区别参见https://fourweekmba.com/bcg-matrix-vs-ansoff-matrix/ 3 Communicating...

Redis(12)| 过期删除策略和内存淘汰策略

Redis 是可以对 key 设置过期时间的&#xff0c;因此需要有相应的机制将已过期的键值对删除&#xff0c;而做这个工作的就是过期键值删除策略。 如何设置过期时间 先说一下对 key 设置过期时间的命令。 设置 key 过期时间的命令一共有 4 个&#xff1a; expire key n&#x…...

Go-服务注册和发现,负载均衡,配置中心

文章目录 什么是服务注册和发现技术选型 Consul 的安装和配置1. 安装2. 访问3. 访问dns Consul 的api接口go操作consulgrpc下的健康检查grpc的健康检查规范动态获取可用端口号 负载均衡策略1. 什么是负载均衡2. 负载均衡策略1. 集中式load balance2. 进程内load balance3. 独立…...

k8s-实验部署 1

1、k8s集群部署 更改所有主机名称和解析 开启四台实验主机&#xff0c;k8s1 仓库&#xff1b;k8s2 集群控制节点&#xff1b; k8s3 和k8s4集群工作节点&#xff1b; 集群环境初始化 使用k8s1作为仓库&#xff0c;将所有的镜像都保存在本地&#xff0c;不要将集群从外部走 仓库…...

Git的原理与使用(一)

目录 Git初始 Git安装 Git基本操作 创建git本地仓库 配置git 工作区,暂存区,版本库 添加文件,提交文件 查看.git文件 修改文件 版本回退 小结 Git初始 git是一个非常强大的版本控制工具.可以快速的将我们的文档和代码等进行版本管理. 下面这个实例看理解下为什么需…...

1204. 错误票据

题目&#xff1a; 1204. 错误票据 - AcWing题库 思路&#xff1a; 将输入的数据存入数组&#xff0c;从小到大排序后遍历&#xff0c;若 (a[i] a[i - 1])res1 a[i]--->重号;若(a[i] - a[i - 1] > 2)res2 a[i] - 1--->断号。 难点&#xff1a;题目只告诉我们输入…...

uniapp中在组件中使用被遮挡或层级显示问题

uniapp中在组件中使用或croll-view标签内使用uni-popup在真机环境下会被scroll-view兄弟元素遮挡&#xff0c;在开发环境下和安卓系统中可以正常显示&#xff0c;但在ios中出现了问题 看了许多文章都没有找到问题的原因&#xff0c;最后看到这一个文章http://t.csdnimg.cn/pvQ…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

基于单片机的宠物屋智能系统设计与实现(论文+源码)

本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢&#xff0c;连接红外测温传感器&#xff0c;可实时精准捕捉宠物体温变化&#xff0c;以便及时发现健康异常&#xff1b;水位检测传感器时刻监测饮用水余量&#xff0c;防止宠物…...