`
悲剧了
  • 浏览: 144454 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

log4j中再次看ThreadLoal用法

阅读更多
   关于ThreadLocal坛子里面ThreadLocal的帖子很多,说法也有好多不一致
每次举例都是hibernate里面的session,这周使用log4j做一些东东,发现log4j的代码用这个ThreadLocal可是清晰多了,而且很有意思。


  log4j里的MDC说起,这个是个键值对存储的容器,在里面加你的键值对,在配置文件配置你输出的格式,需要输出的内容时候取里面的键
如:

            MDC.put("usr_id", usr_id);  
            MDC.put("log_title", "网站访问记录");  
            MDC.put("log_type", "记录");  
            MDC.put("log_title", "网站访问记录");  
            MDC.put("log_datetime", format.format(now));  
            MDC.put("log_ip", log_ip);  

配置文件里面
引用

log4j.appender.project-util-db.sql=insert into user_log (usr_id,log_title,log_category,log_type,log_datetime,log_ip)
VALUES ('%X{usr_id}','%X{log_title}','%X{log_type}','%X{log_title}','%X{log_datetime}','%X{log_ip}')


这个实例MDC.put那个logger实例也MDC.put,里面不是会很崩溃,会覆盖一些东西,越来越大之类的

直接上代码:
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.log4j;

import java.util.Hashtable;
import org.apache.log4j.helpers.Loader;
import org.apache.log4j.helpers.ThreadLocalMap;

/**
   The MDC class is similar to the {@link NDC} class except that it is
   based on a map instead of a stack. It provides <em>mapped
   diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
   MDC in short, is an instrument for distinguishing interleaved log
   output from different sources. Log output is typically interleaved
   when a server handles multiple clients near-simultaneously.

   <p><b><em>The MDC is managed on a per thread basis</em></b>. A
   child thread automatically inherits a <em>copy</em> of the mapped
   diagnostic context of its parent.
  
   <p>The MDC class requires JDK 1.2 or above. Under JDK 1.1 the MDC
   will always return empty values but otherwise will not affect or
   harm your application.
   
   @since 1.2

   @author Ceki G&uuml;lc&uuml; */
public class MDC {
  
  final static MDC mdc = new MDC();
  
  static final int HT_SIZE = 7;

  boolean java1;
  
  Object tlm;
  
  private
  MDC() {
    java1 = Loader.isJava1();
    if(!java1) {
      tlm = new ThreadLocalMap();
    }
  }

  /**
     Put a context value (the <code>o</code> parameter) as identified
     with the <code>key</code> parameter into the current thread's
     context map.

     <p>If the current thread does not have a context map it is
     created as a side effect.
    
   */
  static
  public
  void put(String key, Object o) {
     if (mdc != null) {
         mdc.put0(key, o);
     }
  }
  
  /**
     Get the context identified by the <code>key</code> parameter.

     <p>This method has no side effects.
   */
  static 
  public
  Object get(String key) {
    if (mdc != null) {
        return mdc.get0(key);
    }
    return null;
  }

  /**
     Remove the the context identified by the <code>key</code>
     parameter.

  */
  static 
  public
  void remove(String key) {
    if (mdc != null) {
        mdc.remove0(key);
    }
  }


  /**
   * Get the current thread's MDC as a hashtable. This method is
   * intended to be used internally.  
   * */
  public static Hashtable getContext() {
    if (mdc != null) {
        return mdc.getContext0();
    } else {
        return null;
    }
  }

  /**
   *  Remove all values from the MDC.
   *  @since 1.2.16
  */
  public static void clear() {
    if (mdc != null) {
        mdc.clear0();
    }
  }


  private
  void put0(String key, Object o) {
    if(java1 || tlm == null) {
      return;
    } else {
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
      if(ht == null) {
        ht = new Hashtable(HT_SIZE);
        ((ThreadLocalMap)tlm).set(ht);
      }    
      ht.put(key, o);
    }
  }
  
  private
  Object get0(String key) {
    if(java1 || tlm == null) {
      return null;
    } else {       
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
      if(ht != null && key != null) {
        return ht.get(key);
      } else {
        return null;
      }
    }
  }

  private
  void remove0(String key) {
    if(!java1 && tlm != null) {
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
      if(ht != null) {
        ht.remove(key);
      } 
    }
  }


  private
  Hashtable getContext0() {
     if(java1 || tlm == null) {
      return null;
    } else {       
      return (Hashtable) ((ThreadLocalMap)tlm).get();
    }
  }

  private
  void clear0() {
    if(!java1 && tlm != null) {
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
      if(ht != null) {
        ht.clear();
      } 
    }
  }

}


重点看里面的put方法
  private
  void put0(String key, Object o) {
    if(java1 || tlm == null) {
      return;
    } else {
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
      if(ht == null) {
        ht = new Hashtable(HT_SIZE);
        ((ThreadLocalMap)tlm).set(ht);
      }    
      ht.put(key, o);
    }
  }

先调用ThreadLocalMap.get()获取,注意此处ThreadLocalMap是log4j自己写的继承自ThreadLocal的子类,但get,set方法还是没有覆盖的。
如下代码所示:


   public T get() {
    
        Thread t = Thread.currentThread();
        
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

Thread t = Thread.currentThread();-->>取出当前线程
ThreadLocalMap map = getMap(t);--->>根据当前线程取出里面的变量return t.threadLocals;

  ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

Thread类里面定义
ThreadLocal.ThreadLocalMap threadLocals = null;

可以看出ThreadLocalMap是ThreadLocal的一个内部类,不过这个六百多行的内部类确实不容易看
map.getEntry(this)-->> 在map不为空时候,取出里面存放的实体,为什么传this?
到这一步,已经从当前线程 当前对象 这两个纬度锁定到了这个map,对static class ThreadLocalMap这样一个静态内部类来说, 已经可以控制每个线程分配一个独立占用的虚拟内存地带了,如果其它线程要操作这个,就用这两个纬度去获取

再理一下这种方式的思路
[size=medium]
每个线程有一个ThreadLocalMap,这个是在线程本身就定义的,Thread里面有
ThreadLocal.ThreadLocalMap threadLocals = null;

那么每个线程里面可根据当前对象取出里面的实体。[/size]

这个实体看你自己使用什么就可以指定什么,反正是个object,MDC里面指定为hashtable

最终调用
  public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }


log4j使用上述方式,保证调用MDC的线程实例,通过二个纬度确定里面有唯一一份object(hashtable)









分享到:
评论

相关推荐

    老生常谈Log4j和Log4j2的区别(推荐)

    而Log4j2需要import org.apache.logging.log4j.Level、org.apache.logging.log4j.LogManager和org.apache.logging.log4j.Logger,使用LogManager.getLogger()方法获取日志记录器。 Log4j和Log4j2都是常用的日志记录...

    若依框架使用的log4j2.16.0,修复log4j漏洞log4j2下载最新log4j2.16.0下载

    Log4j是一个广泛使用的Java日志记录框架,它允许开发者在应用程序中轻松地记录各种级别的日志信息,如DEBUG、INFO、WARN、ERROR等。在2021年底,一个重大的安全漏洞(CVE-2021-44228)被发现在Log4j2的早期版本中,...

    Log4j将System.out搞到log4j中输出四

    在《Log4j将System.out搞到log4j中输出四》这篇博文中,作者可能详细讨论了这些步骤,并可能分享了一些实战经验。通过学习这篇博文,读者可以更深入地了解如何在实际项目中实现这一转换,提升日志管理的效率。 总结...

    logging-log4j2-log4j-2.15.0-rc2.zip maven 资源库

    针对Log4j 2 远程代码执行漏洞,需要用到的升级资源包,适用于maven资源库,包括log4j,log4j-core,log4j-api,log4j-1.2-api,log4j-jpa等全套2.15.0 maven资源库jar包。如果是maven本地仓库使用,需要将zip包解压...

    Log4j2简介及与Log4j效率对比

    与Log4j 1.x相比,Log4j2在设计上进行了重大改进,并解决了Logback等其他日志框架中存在的某些体系结构问题。 #### 特性概述 1. **审计功能**:Log4j2设计时考虑到了审计需求,这意味着即使在配置更新过程中,它也...

    Log4j2、Fastjson、Log4j的BurpSuite插件亲测有效

    使用这个BurpSuite插件,可以有效地帮助安全从业者在目标系统中识别出Log4j、Log4j2和Fastjson的使用,并评估是否存在安全风险。无论是老版还是新版的BurpSuite,该插件都能兼容,这意味着它具有良好的兼容性和实用...

    log4j.jar各个版本

    apache-log4j-1.2.15.jar, apache-log4j-extras-1.0.jar, apache-log4j-extras-1.1.jar, apache-log4j.jar, log4j-1.2-api-2.0.2-javadoc.jar, log4j-1.2-api-2.0.2-sources.jar, log4j-1.2-api-2.0.2.jar, log4j-...

    log4j中文手册.pdf

    《log4j中文手册》是Java开发人员必备的参考资料,它详细介绍了log4j这个广泛使用的日志记录框架。Log4j是Apache软件基金会开发的一个开源项目,主要用于生成应用程序运行时的日志信息,帮助开发者进行调试、性能...

    Log4j2学习用到的jar包及apache-log4j-2.19.0-bin.zip

    分别有disruptor-3.3.4.jar(Log4j2异步日志的底层实现)、log4j-api-2.19.0.jar(log4j门面)、log4j-core-2.19.0.jar(log4j实现)、log4j-slf4j-impl-2.19.0.jar(SLF4J与Log4j绑定)、slf4j-api-1.7.30.jar(SLF...

    SSM整合中的Log4j日志的配置详情

    Log4j 是一个功能强大且广泛使用的日志记录工具,特别是在 SSM(Spring、Spring MVC、Mybatis)整合项目中,合理地配置 Log4j 对项目的日志记录和输出至关重要。本文将详细介绍 SSM 整合中的 Log4j 配置详情,帮助...

    log4j+slf4j实现 log4j测试代码,log4j+slf4j实现 log4j测试代码

    Log4j和SLF4J(Simple Logging Facade for Java)是两个广泛使用的日志框架,它们各有优势并常被一起使用以提供更灵活的日志解决方案。本文将详细探讨如何通过SLF4J接口来使用Log4j进行日志记录,并展示一个测试代码...

    log4j中文手册(中文版)

    ### log4j中文手册知识点概览 ...综上所述,`log4j`是一款强大且灵活的日志记录工具,通过上述知识点的学习,我们不仅可以快速掌握其基础使用方法,还能深入理解其内部机制,更好地应用于实际项目中。

    log4j-api-2.12.4.ja和log4j-core-2.12.4.jar

    Log4j是Java编程语言中最常用的日志记录框架之一,由Apache软件基金会开发。它提供了灵活的日志记录功能,使得开发者能够轻松地控制日志信息的输出格式、输出位置以及输出级别。此次提及的`log4j-api-2.12.4.jar`和`...

    log4j-API-最新稳定版本log4j-1.2.17

    描述中再次确认了这是Apache Log4j的API,并强调是“最新稳定版本”。尽管这里提到的1.2.17在某些情况下可能不是当前的最新版本,但在发布时,它可能被认为是稳定且推荐使用的版本。 **标签:log4j-API** 标签"log...

    log4j配置和加载方法

    ### Log4j配置与加载方法详解 Log4j是一款由Apache出品的日志记录工具,它提供了灵活的日志级别控制和多样化的日志输出方式,广泛应用于Java应用的开发中。本文将深入解析log4j的配置与加载机制,帮助开发者更好地...

    示范如何在android工程中使用log4j记录日志

    3. **初始化Log4j**:在Application类的onCreate方法中初始化Log4j,确保在使用日志之前完成配置加载: ```java @Override public void onCreate() { super.onCreate(); Log4jConfig.init(this); } ``` 4. *...

    SpringBoot框架配置log4j和log4j2的配置代码

    Log4j和Log4j2是两种广泛使用的Java日志框架,它们提供了灵活的日志配置和高性能的日志处理能力。本文将详细介绍如何在SpringBoot项目中配置Log4j和Log4j2。 ### SpringBoot与Log4j Log4j是Apache的一个开源项目,...

    log4j中配置日志文件相对路径方法(PDF)

    ### Log4j中配置日志文件相对路径方法详解 #### 概述 在软件开发过程中,日志记录是一项重要的功能,它有助于开发者调试程序、监控应用程序的运行状态以及追踪问题。`Log4j`作为一款优秀的日志管理工具,被广泛应用...

    log4j-core-2.15.0.jar log4j-2.15.0-rc2

    Apache log4j2零日漏洞,根据 log4j-2.15.0-rc2 版本编译生成log4j-api-2.15.0.jar 1.解压你的jar jar xvf XXX.jar 2. 删除旧版本jar cd ./BOOT-INF/lib rm -rf log4j-api-*.jar 3. 上传新版本log4j-api-2.15.0....

    log4j示例项目

    这个“log4j示例项目”旨在帮助开发者理解和使用Log4j,通过该项目,我们可以深入学习Log4j的配置、使用方法以及其在实际开发中的应用。 **1. Log4j的组成部分** Log4j主要包括三个核心组件:Logger(日志器)、...

Global site tag (gtag.js) - Google Analytics