log4j日志配置%X{TransId}
log4j日志配置文件中的%X{TransId}是怎么动态获取值的
在Log4j中,%X{TransId}
是用来从MDC(Mapped Diagnostic Context)中获取值的占位符。MDC 是 Log4j 提供的一种机制,用于在同一个线程的不同日志记录中传递上下文信息。通过 MDC,你可以在日志中添加一些动态的上下文信息,比如事务ID、用户ID等。
要动态设置 TransId
的值,你需要在代码中使用 MDC.put
方法。以下是一个示例:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;public class Log4jExample {private static final Logger logger = LogManager.getLogger(Log4jExample.class);public static void main(String[] args) {// 设置TransId的值ThreadContext.put("TransId", "12345");// 记录日志logger.info("This is a log message with TransId.");// 清除TransId的值ThreadContext.clearMap();}
}
在上面的代码中,我们使用 ThreadContext.put("TransId", "12345")
来设置 TransId
的值。然后在日志配置文件中使用 %X{TransId}
占位符来引用这个值。
例如,log4j2.xml 配置文件可以这样配置:
<Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg %X{TransId}%n"/></Console></Appenders><Loggers><Root level="info"><AppenderRef ref="Console"/></Root></Loggers>
</Configuration>
在这个配置中,%X{TransId}
会被替换为 ThreadContext
中 TransId
的值,即 12345
。
总结:通过在代码中使用 ThreadContext.put("TransId", "value")
方法设置 TransId
的值,然后在日志配置文件中使用 %X{TransId}
占位符来引用这个值,从而实现动态获取和记录 TransId
。
在Log4j 2中,ThreadContext
是用来替代 Log4j 1.x 中的 MDC
的。对于 Log4j 1.x,你需要使用 MDC.put
方法来设置上下文信息。以下是使用 Log4j 1.x 的示例:
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;public class Log4jExample {private static final Logger logger = Logger.getLogger(Log4jExample.class);public static void main(String[] args) {// 设置TransId的值MDC.put("TransId", "12345");// 记录日志logger.info("This is a log message with TransId.");// 清除TransId的值MDC.clear();}
}
在上面的代码中,我们使用 MDC.put("TransId", "12345")
来设置 TransId
的值。然后在日志配置文件中使用 %X{TransId}
占位符来引用这个值。
例如,log4j.properties 配置文件可以这样配置:
log4j.rootLogger=INFO, Consolelog4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1} - %m %X{TransId}%n
在这个配置中,%X{TransId}
会被替换为 MDC
中 TransId
的值,即 12345
。
总结:对于 Log4j 1.x,通过在代码中使用 MDC.put("TransId", "value")
方法设置 TransId
的值,然后在日志配置文件中使用 %X{TransId}
占位符来引用这个值,从而实现动态获取和记录 TransId
。对于 Log4j 2.x,使用 ThreadContext.put
方法来实现相同的功能。
ThreadLocal
是 Java 提供的一种机制,用于在每个线程中存储独立的变量副本。它可以确保变量在多线程环境下的线程安全性,而不需要显式的同步。每个线程都可以独立地修改自己的副本,而不会影响其他线程的副本。
ThreadLocal
的基本原理
-
独立副本:每个线程都有一个独立的变量副本,这些副本存储在
ThreadLocal
对象中。每个线程对其副本的修改不会影响其他线程的副本。 -
内部存储:
ThreadLocal
通过Thread
类中的一个内部ThreadLocalMap
来存储每个线程的变量副本。ThreadLocalMap
是一个自定义的哈希表,键是ThreadLocal
对象,值是线程的变量副本。 -
访问机制:当线程访问
ThreadLocal
变量时,ThreadLocal
会根据当前线程获取对应的变量副本。如果当前线程没有对应的副本,ThreadLocal
会创建一个新的副本并存储在ThreadLocalMap
中。
ThreadLocal
的主要方法
get()
:返回当前线程的变量副本。如果当前线程没有对应的副本,则调用initialValue()
方法创建一个新的副本。set(T value)
:设置当前线程的变量副本。remove()
:移除当前线程的变量副本,防止内存泄漏。
示例代码
以下是一个简单的示例,展示了如何使用 ThreadLocal
:
public class ThreadLocalExample {// 创建一个ThreadLocal变量private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);public static void main(String[] args) {// 创建两个线程Thread thread1 = new Thread(() -> {for (int i = 0; i < 5; i++) {threadLocal.set(threadLocal.get() + 1);System.out.println(Thread.currentThread().getName() + " - " + threadLocal.get());}});Thread thread2 = new Thread(() -> {for (int i = 0; i < 5; i++) {threadLocal.set(threadLocal.get() + 1);System.out.println(Thread.currentThread().getName() + " - " + threadLocal.get());}});thread1.start();thread2.start();}
}
在这个示例中,每个线程都有一个独立的 ThreadLocal
变量副本,互不干扰。
内部实现
ThreadLocal
的内部实现主要依赖于 ThreadLocalMap
,这是一个自定义的哈希表,存储在每个线程的 Thread
对象中。以下是一些关键点:
-
ThreadLocalMap:
ThreadLocalMap
是ThreadLocal
的静态内部类,用于存储每个线程的变量副本。它使用ThreadLocal
对象作为键,变量副本作为值。 -
Entry:
ThreadLocalMap
中的每个条目是一个Entry
对象,包含一个弱引用的ThreadLocal
键和一个强引用的值。 -
垃圾回收:由于
ThreadLocal
键是弱引用,当ThreadLocal
对象被垃圾回收时,ThreadLocalMap
中对应的条目会被自动清除,防止内存泄漏。
内存泄漏问题
使用 ThreadLocal
时需要注意内存泄漏问题。由于 ThreadLocalMap
中的键是弱引用,但值是强引用,如果不显式调用 remove()
方法,可能会导致内存泄漏。因此,建议在使用完 ThreadLocal
变量后,显式调用 remove()
方法清除变量副本。
threadLocal.remove();
总结:ThreadLocal
提供了一种在多线程环境下存储和访问独立变量副本的机制,确保线程安全性。其内部通过 ThreadLocalMap
实现,每个线程都有一个独立的变量副本。使用时需要注意内存泄漏问题,建议在使用完后显式调用 remove()
方法清除变量副本。
ThreadLocalMap
是 ThreadLocal
类的一个静态内部类,用于存储每个线程的变量副本。它是 ThreadLocal
实现的核心部分。ThreadLocalMap
通过在每个线程的 Thread
对象中维护一个哈希表来实现这一功能。
ThreadLocalMap
的结构
ThreadLocalMap
是一个自定义的哈希表,包含以下几个关键部分:
-
Entry:
ThreadLocalMap
中的每个条目是一个Entry
对象。Entry
是ThreadLocalMap
的静态内部类,包含一个弱引用的ThreadLocal
键和一个强引用的值。static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;} }
-
Table:
ThreadLocalMap
使用一个数组table
来存储Entry
对象。数组的大小是2的幂次方,以便于哈希冲突的处理。private Entry[] table;
-
Threshold:
ThreadLocalMap
维护一个阈值threshold
,用于控制何时进行扩容。默认情况下,阈值是数组大小的2/3。private int threshold;
ThreadLocalMap
的主要方法
-
set():将值存储到
ThreadLocalMap
中。如果键已经存在,则更新值;如果键不存在,则插入新的条目。private void set(ThreadLocal<?> key, Object value) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len - 1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();if (k == key) {e.value = value;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);int sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash(); }
-
get():从
ThreadLocalMap
中获取值。如果键存在,则返回对应的值;如果键不存在,则返回null
。private Object getEntry(ThreadLocal<?> key) {int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];if (e != null && e.get() == key)return e.value;elsereturn getEntryAfterMiss(key, i, e); }
-
remove():从
ThreadLocalMap
中移除键值对。private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len - 1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();expungeStaleEntry(i);return;}} }
内存泄漏问题
由于 ThreadLocalMap
中的键是弱引用,当 ThreadLocal
对象被垃圾回收时,键会变成 null
,但值仍然存在。这可能导致内存泄漏。因此,建议在使用完 ThreadLocal
变量后,显式调用 remove()
方法清除变量副本。
threadLocal.remove();
总结
ThreadLocalMap
是ThreadLocal
的静态内部类,用于存储每个线程的变量副本。Entry
是ThreadLocalMap
的静态内部类,包含一个弱引用的ThreadLocal
键和一个强引用的值。ThreadLocalMap
使用一个数组table
来存储Entry
对象,并通过哈希算法和线性探测解决哈希冲突。- 主要方法 包括
set()
、get()
和remove()
,用于存储、获取和移除键值对。 - 内存泄漏问题:由于键是弱引用,值是强引用,建议在使用完
ThreadLocal
变量后显式调用remove()
方法清除变量副本。
相关文章:

log4j日志配置%X{TransId}
log4j日志配置文件中的%X{TransId}是怎么动态获取值的 在Log4j中,%X{TransId} 是用来从MDC(Mapped Diagnostic Context)中获取值的占位符。MDC 是 Log4j 提供的一种机制,用于在同一个线程的不同日志记录中传递上下文信息。通过 M…...
PHP模拟高并发异步请求测试+redis的setnx处理并发和防止死锁处理
/** PHP并发异步请求测试* /test/curlMulti*/public function curlMultiAction(){$urls ["http://localhost:801/api/order/create","http://localhost:801/api/order/create","http://localhost:801/api/order/create","http://localhos…...

访问网站出现“此站点不安全”如何解决
在网络浏览中,我们经常会遇到浏览器地址栏出现“此站点不安全”的警告。这通常意味着网站没有使用SSL(安全套接层)加密来保护用户数据的安全。那么,如何通过获得并安装SSL证书来消除这一警告,确保网站的安全可靠呢&…...

同一台电脑同时连接使用Gitee(码云)和Github
1、添加对应的密钥 ssh-keygen -t rsa -C "your_emailexample.com" -f ~/.ssh/github_id-rsa //生成github秘钥 ssh-keygen -t rsa -C "your_emailexample.com" -f ~/.ssh/gitee_id-rsa //生成码云秘钥 2、在 ~/.ssh 文件里会生成对应的文件 文件夹里会…...
GORM 插入和批量插入操作介绍
GORM 是一个功能强大的 Go 语言 ORM 库,它提供了简单易用的 API 来执行数据库操作。本文将介绍如何使用 GORM 进行单条记录插入和批量插入操作。 单条记录插入 在 GORM 中,插入一条记录非常简单。首先,你需要定义一个模型,该模型…...

企业CAD图纸加密软件推荐!2024年好用的10款CAD图纸加密软件排行
在现代企业中,CAD图纸作为重要的设计和工程数据,其安全性和保密性至关重要。为了防止图纸被非法获取、篡改或滥用,选择一款高效的CAD图纸加密软件显得尤为重要。本文将为您推荐2024年市场上十款好用的CAD图纸加密软件,帮助企业保护…...

智能电梯标志新时代:墨水屏电子标签引领变革
电梯安全墨水屏标签的智能设备悄然出现在各大写字楼和住宅区的电梯中,引发了广泛关注。这款设备替代了传统的纸质电梯标志,通过手机蓝牙标签APP直接进行编辑刷新内容,并具备Type-C接口充电功能。 本文将深入探讨这一创新技术的应用前景及其对…...
使用nvm下载nodejs版本报错
这里写自定义目录标题 使用nvm下载nodejs版本报错:Error retrieving "http://npm.taobao.org/mirrors/node/latest/SHASUMS256.txt": HTTP Status 404问题原因解决办法 使用nvm下载nodejs版本报错:Error retrieving “http://npm.taobao.org/m…...
深入理解CSS的:valid和:invalid伪类:增强表单验证的艺术
在现代网页设计中,用户输入验证是一个重要的环节,它不仅关乎用户体验,也是数据准确性和安全性的保障。CSS3引入了两个强大的伪类选择器::valid和:invalid,它们允许开发者通过CSS来增强表单输入的验证过程,而…...

稚晖君发布5款全能人形机器人,开源创新,全能应用
8月18日,智元机器人举行“智元远征 商用启航” 2024年度新品发布会,智元联合创始人彭志辉主持并发布了“远征”与“灵犀”两大系列共五款商用人形机器人新品——远征A2、远征A2-W、远征A2-Max、灵犀X1及灵犀X1-W,并展示了在机器人动力、感知、…...

【总结】冲击偶的概念与性质
冲击偶的概念与性质...

Hbase图形化界面
分享一个好用的hbase图形化界面 安装包:链接: https://pan.baidu.com/s/11Y2cDlme-P2xe--pYqy6MQ?pwdguag 提取码: guag 1、上传项目到linux 2、修改数据库配置信息 application-druid.yml 修改url、username、password为数据库连接信息 3、创建数据库(注意字符集…...

PhalApi:在宝塔一键安装部署PHP开源接口框架的教程
如何在宝塔上,一键安装部署PhalApi开源接口框架? 第一步,进入你的宝塔 - 软件商店。 第二步,切换到:一键部署; 第三步,搜索 phalapi; 第四步,点击 一键部署࿱…...
什么是BERT?工程快速入门
基本介绍 全称是Bidirectional Encoder Representations from Transformers。BERT翻译成中文通常被称为“双向编码器表征法”或简单地称为“双向变换器模型” Bidirectional:是双向神经网络,这个在学习 RNN 时候我们就了解到如何使用双向 RNN 让每一个…...
SQL - 事务
事务是代表单个工作单元的一组SQL语句,当我们需要对数据库进行多次更改的情况下,要使用事务,我们希望所有这些更改作为一个单元一起成功或失败事务属性 (ACID) 原子性(Atomicity):事务中的所有操作要么全部完成,要么全…...
系统, 安装完以后只能进ubuntu
1.问题 在已经安装了Windows10系统的情况下,用U盘安装Ubuntu 16.04双系统, 安装完以后只能进ubuntu,在grub系统选择界面,Windows10操作系统的选项都没有。 2.解决办法 进入ubuntu系统,打开终端输入: sudo update-g…...

闲鱼功能全解析:闲置物品快速变现
咸鱼(现已更名为闲鱼)作为一款闲置交易平台,其功能设计旨在提供一个方便、安全的环境,让用户能够轻松地买卖二手物品。以下是对咸鱼(闲鱼)功能的详细分析 1. 商品发布与管理 商品发布:用户可以…...
牛客网SQL进阶129 :月均完成试卷数不小于3的用户
月均完成试卷数不小于3的用户爱作答的类别_牛客题霸_牛客网 0 问题描述 基于试卷作答记录表exam_record、试卷信息表examination_info ,统计出 “月均完成试卷数”不小于3的用户作答的类别及作答次数,按次数降序输出。 1 数据准备 drop table if exis…...

Astro + Cloudflare Pages 快速搭建个人博客
目录 1 选择 Astro 模板2 使用代码3 修改代码4 上传 Github5 部署 Cloudflare Pages6 后续修改 最近我搭建完了我的个人网站,很多人问是怎么做的,今天就来写一篇教程吧。 全部干货,看完绝对能成功搭建自己的网站!(还不…...
Vue中<style scoped>与<style module>的深入解析与应用
在Vue开发中,样式管理是一个重要的环节。Vue提供了多种方式来帮助开发者更有效地管理组件样式,其中<style scoped>和<style module>是两个非常实用的特性。本文将深入探讨这两个属性的作用、原理以及使用场景,帮助读者更好地理解…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...

基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...