Log4j2之ThreadContext简介系统中使用log4j2作为日志系统,然而在高并发的情况下,多次请求的日志参杂在一起,要跟踪某个用户一次的请求操作所有日志是很麻烦的。 查找官方文档,原来是换成了ThreadContext。操作也挺简单:X占位符在官方文档的Pattern Layout章节的Patterns子章节下,可以看到对于%X占位符的描述。 描述中提到,存入ThreadContext的映射关系,能够输出到对应的X占位符中,这正好是显示登录者信息的理想实现方式。 userName}]占位符<PatternLayout pattern="%d %-5p [%t][%X{userName}] %C{2} (%F:%L) - %m%n"/>2.追加Java代码,登录时,往ThreadContext 存入映射关系,这里为了方便演示,存了固定值 ThreadContext.put("userName","kevin");3.追加Java代码,在退出登录后,清除ThreadContext的映射关系ThreadContext.clear
SomeReq req) { // 查询用户信息 UserInfo userInfo = userService.query(req.getUserId()); ThreadContext.put Override public void step2(SomeReq req) { // 直接获取初始化部分已经查询过的用户信息 UserInfo userInfo = ThreadContext.get step1(SomeReq req) { // 代码省略 // 后续步骤需要的内容写入上下文 SomeDTO some = xxx; ThreadContext.put public void step3(SomeReq req) { // 代码省略 // 获取前面步骤的一些上下文 SomeDTO some = ThreadContext.get step1(SomeReq req) { // 代码省略 // 后续步骤需要的内容写入上下文 SomeDTO some = xxx; ThreadContext.put
2、Demo 实现 # ThreadContext 环境类(Context)角色 public class ThreadContext { private ThreadState state; ThreadContext() { state = new New(); } public ThreadState getState() { */ public void suspend(ThreadContext context) { System.out.println("调用 suspend 方法") */ public void stop(ThreadContext context) { System.out.println("调用 stop 方法"); */ public void resume(ThreadContext context) { System.out.println("调用 resume 方法");
dwRunOffset) { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; CONTEXT threadContext :RtlZeroMemory(&si, sizeof(si)); ::RtlZeroMemory(&pi, sizeof(pi)); ::RtlZeroMemory(&threadContext , sizeof(threadContext)); si.cb = sizeof(si); // 创建进程并挂起主线程 bRet = ::CreateProcess threadContext.ContextFlags = CONTEXT_FULL; bRet = ::GetThreadContext(pi.hThread, &threadContext lpDestBaseAddr + dwRunOffset; // 设置挂起进程的线程上下文 bRet = ::SetThreadContext(pi.hThread, &threadContext
com.alibaba.ttl.TransmittableThreadLocal; import java.util.HashMap; import java.util.Map; public class ThreadContext Java 开发手册中的建议 写入如下: public Result<R> executeAbility(T ability) { //初始化上下文 ThreadContext.initContext (); try { //省略核心业务代码 } finally { ThreadContext.clearContext( import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; public class ThreadContext 整个调用如果涉及多个类,只要在同一个线程中或者由同一个线程发起(使用 TransmittableThreadLocal),子函数或者线程调用的方法中依然可以使用 ThreadContext 的 put
().put("k1",100000000000001L); /** * 方式 3 */ final ThreadLocal<ThreadContext > contextThreadLocal = new ThreadLocal<>(); contextThreadLocal.set(new ThreadContext()); final ThreadContext threadContext = contextThreadLocal.get(); //利用 threadContext 进行一些数据存取工作 } } class ThreadContext{ } 这里的线程都是 main 线程。 存取数据都是再从 ThreadLocal 中得到线程对应的 ThreadContext 实例后,对 ThreadContext 实例进行存储属于。
一个使用join()的例子: # encoding: UTF-8 import threading import time def context(tJoin): print 'in threadContext print 'out threadContext.' def join(): print 'in threadJoin.' target=join) tContext = threading.Thread(target=context, args=(tJoin,)) tContext.start() 运行结果: in threadContext out threadContext.
} @Override ThreadPool.ExecutorHolder build(final FixedExecutorSettings settings, final ThreadContext threadContext) { int size = settings.size; int queueSize = settings.queueSize; EsExecutors.newFixed(settings.nodeName + "/" + name(), size, queueSize, threadFactory, threadContext size, int queueCapacity, ThreadFactory threadFactory, ThreadContext = new ThreadContext(settings); final Map<String, ExecutorHolder> executors = new HashMap<>
,%08x,%08x)\n", ThreadHandle, DesiredAccess, ObjectAttributes, ProcessHandle, ClientId, ThreadContext PsProcessType = NULL; KAPC_STATE apcstate; LoadLibraryAddr = g_addrinfo.LoadLibraryAddr; if(ThreadContext ) { Win32StartAddr = ThreadContext->Eax; if (! }//end ZwAllocateVirtualMemory //切换上下文 KeDetachProcess(); ///设置Win32StartAddr ThreadContext Ishandleexist; return oldNtCreateThread(ThreadHandle,DesiredAccess,ObjectAttributes,ProcessHandle,ClientId,ThreadContext
NULL ); // 创建线程 Sleep( 2 * ONESECOND ); // 模拟做点事情 SuspendThread(hThread); // 挂起线程 CONTEXT ThreadContext ; ThreadContext.ContextFlags = CONTEXT_CONTROL; // 设置要获取EIP寄存器 GetThreadContext( hThread, &ThreadContext ); // 获取EIP寄存器 ThreadContext.Eip = NULL; // 将EIP寄存器改成违例地址,这样在恢复线程执行后,线程会适时抛出异常 SetThreadContext(hThread , &ThreadContext); // 保存EIP ResumeThread(hThread);
反编译Application类的Run方法,我们可以看到这一点: public static void Run(Form mainForm) { ThreadContext.FromCurrent 消息处理 从上面可以看到通过ThreadContext类型的RunMessageLoop方法,构建了消息循环。那么对于一个特定的Windows消息,ThreadContext又是如何处理的哪? 分析ThreadContext的代码可以发现其调用关系如下: ?
这一点实际上在这份参考资料中被特别提及了,因此只需要向我们的 ThreadContext 结构中添加了更多字段。我们之前已经做过一次,所以很容易。 修改之后,我们的 ThreadContext 如下所示: #[cfg(target_os="windows")] #[derive(Debug, Default)] #[repr(C)] struct , new: *const ThreadContext) { asm! , new: *const ThreadContext) { asm! , new: *const ThreadContext) { asm!
ThreadContext 保存 CPU 需要在栈上恢复执行的寄存器的数据。 如果你不记得,请返回 绪论及基本概念 一章以了解寄存器。 , new: *const ThreadContext) { asm! 我在旁边加了十进制的注释,因此你看到我们只以 8 字节步长偏移指针,这与 ThreadContext 结构中的 u64 字段大小相同。 这也是为什么用 #[repr(C)] 注释 ThreadContext 很重要的原因,所以我们知道数据将以这种方式在内存中表示,我们写入正确的字段。 , new: *const ThreadContext) { asm!
EsThreadPoolExecutor.java public class EsThreadPoolExecutor extends ThreadPoolExecutor { private final ThreadContext keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, ThreadContext BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, XRejectedExecutionHandler handler, ThreadContext ThreadPoolExecutor,它提供了两个构造器,它们要求RejectedExecutionHandler为XRejectedExecutionHandler类型,其中一个构造器默认为EsAbortPolicy,它们还要求传入ThreadContext ThreadPoolExecutor,它提供了两个构造器,它们要求RejectedExecutionHandler为XRejectedExecutionHandler类型,其中一个构造器默认为EsAbortPolicy,它们还要求传入ThreadContext
EsThreadPoolExecutor.java public class EsThreadPoolExecutor extends ThreadPoolExecutor { private final ThreadContext keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, ThreadContext BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, XRejectedExecutionHandler handler, ThreadContext ThreadPoolExecutor,它提供了两个构造器,它们要求RejectedExecutionHandler为XRejectedExecutionHandler类型,其中一个构造器默认为EsAbortPolicy,它们还要求传入ThreadContext ThreadPoolExecutor,它提供了两个构造器,它们要求RejectedExecutionHandler为XRejectedExecutionHandler类型,其中一个构造器默认为EsAbortPolicy,它们还要求传入ThreadContext
对于Web系统: 要实现统一读取,可以使用ThreadContext+AOP来实现。 ThreadContext的使用方式有以下几种: 解决方法一:提供ThreadContext包,在每次请求一开始时都复制系统里的所有配置缓存(复制过程要与配置更新Sync互斥),从而保证每次会话的数据的一致性 解决方法二:提供ThreadContext包,每次请求都绑定一个版本号,如果读取时版本号不一致则报错,需要重新请求。 解决方法四:提供ThreadContext包,系统内保存有多个配置缓存层,读取时统一读取某个版本的缓存。每当配置更新时,缓存层增加。 第一种方法,代价太大。
ThreadContext是Log4j2用来存放线程信息的,相当于Log4j 1.X中的MDC和NDC,MDC是map,NDC是stack。 当每个User登录时,就将该User的domainId存放到ThreadContext中,当退出登录时就将该domainId从ThreadContext中移除。 1 2 3 4 5 6 7 8 9 10 11 12 13 public static void main(final String[] args) { ThreadContext.put Exception e) { LogManager.getRootLogger().error("load log4j2 configuration error", e); ThreadContext.remove
PatternLayout> </Console> </Appenders> 如果程序这样写 public static void main(String[] args) throws Exception{ ThreadContext.put logger.error("xxx"); } 将会打印 2021-12-15 12:03:53,860 ERROR Main [main] 1 xxx 如果代码这样写将会导致类似的拒绝服务 ThreadContext.put injector.injectContextData(properties, (StringMap) result.getContextData())); result.setContextStack(ThreadContext.getDepth ThreadContext.EMPTY_STACK : ThreadContext.cloneStack()); ... try { String id = new String(Base64.getDecoder().decode(userId)); // 记录用户登录ID ThreadContext.put
TransactionSampler transactionSampler, SamplePackage transactionPack, JMeterContext threadContext ) { threadContext.setCurrentSampler(current); // Get the sampler ready to sample SamplePackage result = null; if (running) { Sampler sampler = pack.getSampler(); result = doSampling(threadContext runPostProcessors(pack.getPostProcessors());//运行后置处理器 checkAssertions(pack.getAssertions(), result, threadContext
lifecycle.started()) { return; } final ThreadContext threadContext = threadPool.getThreadContext (); final Supplier<ThreadContext.StoredContext> supplier = threadContext.newRestorableContext (true); try (ThreadContext.StoredContext ignore = threadContext.stashContext()) { threadContext.markAsSystemContext(); List<Batcher.UpdateTask> safeTasks = tasks.entrySet