zoukankan      html  css  js  c++  java
  • log4j源码解析

    前言:本文将在slf4j的基础上解释log4j的应用,阅读本文前可先行阅读SLF4J源码解析-LoggerFactory(二)

    前言概要

    在前言中提到的slf4j的基础,其主要是通过logback的api来解释slf4j的工作原理,而本文的log4j与logback不同,其可以和slf4j结合使用,也可以脱离slf4j单独使用。

    Maven依赖

    		<dependency>
    			<groupId>org.slf4j</groupId>
    			<artifactId>slf4j-api</artifactId>
    			<version>1.6.6</version>
    		</dependency>
    		<dependency>
    			<groupId>org.slf4j</groupId>
    			<artifactId>slf4j-log4j12</artifactId>
    			<version>1.6.6</version>
    		</dependency>
    		<dependency>
    			<groupId>log4j</groupId>
    			<artifactId>log4j</artifactId>
    			<version>1.2.16</version>
    		</dependency>
    

    此依赖包含了可以使用slf4j对应的扩展方法获取日志对象,也可以独立使用log4j本身的日志对象

    第一种方式-结合slf4j使用

    调用方式如下

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("test") ;
    

    由上可知是通过LoggerFactory#getLogger()方法来获取日志对象,我们分析过其是通过StaticLoggerBinder.getSingleton().getLoggerFactory()工厂类来获取日志对象的,其中StaticLoggerBinder一般都是供其他整合jar来实现的,本文特指slf4j-log4j12-1.6.6.jar。我们看下log4j是如何处理的

    log4j获取LoggerFactory对象

    直接看log4j对StaticLoggerBinder的复写

      private StaticLoggerBinder() {
        //直接使用的是Log4jLoggerFactory工厂类来获取日志对象
        loggerFactory = new Log4jLoggerFactory();
        try {
          Level level = Level.TRACE;
        } catch (NoSuchFieldError nsfe) {
          Util
              .report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
        }
      }
    

    可以看出其是通过Log4jLoggerFactory来获取日志对象的。

    Log4jLoggerFactory获取日志对象

    先看下其构造函数

      public Log4jLoggerFactory() {
        //缓存对象
        loggerMap = new HashMap();
      }
    

    再看确切方法源码

      public Logger getLogger(String name) {
        Logger slf4jLogger = null;
        // protect against concurrent access of loggerMap
        synchronized (this) {
            slf4jLogger = (Logger) loggerMap.get(name);
          if (slf4jLogger == null) {
            org.apache.log4j.Logger log4jLogger;
            if(name.equalsIgnoreCase(Logger.ROOT_LOGGER_NAME)) {
               log4jLogger = LogManager.getRootLogger();
            } else {
              log4jLogger = LogManager.getLogger(name);
            }
            slf4jLogger = new Log4jLoggerAdapter(log4jLogger);
            loggerMap.put(name, slf4jLogger);
          }
        }
        return slf4jLogger;
      }
    

    最终日志对象都是通过LogManager.getLogger()方法来获取到的,上述的Log4jLoggerAdapter只是slf4j-api下Logger的接口实现类,此处类似于针对于log4j的适配器。

    第二种方式-独立使用

    直接采用log4j本身自带的日志工厂类来获取,使用方式如下

    private static final org.apache.log4j.Logger log = org.apache.log4j.LogManager("test");
    

    log4j的加载逻辑的实现均可以通过LogManager类来查看,本文则不进行简析了,此处只作总结

    1. 读取系统变量log4j.defaultInitOverride,如果没指定或者指定的值为false则继续读取。默认为false

    2. 读取系统变量log4j.configuration,如果指定了配置文件路径则读取,反之则往下

    3. 读取classpath路径下的log4j.xml,如果不存在则继续往下

    4. 读取classpath路径下的log4j.properties,找不到则打印警告信息

    5. 其中关于配置文件的加载类也可以自行指定,由系统变量log4j.configurationClass指定

    小结

    1. log4j是我们常用的日志打印工具,本文在slf4j的基础上简单的分析了log4j日志工具的使用,不管是结合slf4j还是独立使用自身的api,均是通过log4j-api中的LogManager#getLogger()来获取日志对象

    2. 其中对于log4j的配置文件读取可见本文的详细内容

  • 相关阅读:
    APP 打包成功的四种方法 转自
    设置启动页
    大数据之医疗行业数据分析
    实验三(FCFS ,SJF,HRRN)
    实验四 用信号量解决进程互斥与同步问题
    实验二 (3)最短作业优先调度
    实验二 (2)优先数调度
    实验二 (1)先来先服务进程调度
    实验一
    Hdoj 1253
  • 原文地址:https://www.cnblogs.com/question-sky/p/7469596.html
Copyright © 2011-2022 走看看