【日志】剖析log4j为什么能找到log4j.properties?

问:log4j为什么能找到log4j.properties 或者 xml?

一、简单粗暴的学习法子:

1、直接在全工程中搜索 “log4j.properties”,你会找到相应字段的位置:

package org.apache.log4j;
public class LogManager {

  /**
   * @deprecated This variable is for internal use only. It will
   * become package protected in future versions.
   * */
  static public final String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
  
  static final String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";  

2、 直接在当前类 LogManager内搜索字段“DEFAULT_CONFIGURATION_FILE” 看下哪个地方用到了。

public class LogManager {
...
static {
	...
   if(configurationOptionStr == null) {	
	url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
	if(url == null) {
	  url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
	}
	...
}
...
}

看到这,那么就得想到这是 LogManager内部的一个静态方法块,意思是只要LogManager这个类一被加载,那么就肯定会去加载 log4j.properties 或者 log4j.xml 配置文件。

3、OK,直接看一个最简单的例子

import org.apache.log4j.Logger;
public class Demo {
	// 点开这个方法
    private static Logger logger = Logger.getLogger(Demo.class);
    public static void main(String[] args) throws Exception {
    	logger.error("123“);
    }
}

4、直接点开 Logger.getLogger(Demo.class);

public class Logger extends Category {
...
  static public Logger getLogger(Class clazz) {
    return LogManager.getLogger(clazz.getName());
  }
}
...

看到 LogManager被使用了吧,那么肯定就会去加载log4j.properties 或者 log4j.xml 配置文件。

二、探寻配置文件中的property如何被加载使用

1、一个简单的配置文件demo(log4j.properties)

log4j.rootLogger=info,stdout,rollingLog

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p (%c{1}#%M:%L) %t - %m%n
log4j.appender.stdout.Threshold=error

## rolling log file
log4j.appender.rollingLog.File=/Users/Documents/temp/logs/rolling.log
log4j.appender.rollingLog.MaxFileSize=512MB
log4j.appender.rollingLog.MaxBackupIndex=12
log4j.appender.rollingLog.Threshold=info
log4j.appender.rollingLog.layout=org.apache.log4j.PatternLayout
log4j.appender.rollingLog.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p (%c{1}#%M:%L) %t - %m%n
log4j.appender.rollingLog=org.apache.log4j.RollingFileAppender

2、依旧简单粗暴的方法,直接工程查找字符串“log4j.rootLogger”,直接找到:

package org.apache.log4j;
public class PropertyConfigurator implements Configurator {

  /**
     Used internally to keep track of configured appenders.
   */
  protected Hashtable registry = new Hashtable(11);  
  private LoggerRepository repository;
  protected LoggerFactory loggerFactory = new DefaultCategoryFactory();

  static final String      CATEGORY_PREFIX = "log4j.category.";
  static final String      LOGGER_PREFIX   = "log4j.logger.";
  static final String       FACTORY_PREFIX = "log4j.factory";
  static final String    ADDITIVITY_PREFIX = "log4j.additivity.";
  static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
  // ================================================================================
  static final String ROOT_LOGGER_PREFIX   = "log4j.rootLogger"; // 字段在这里!!!!
  // ================================================================================
  static final String      APPENDER_PREFIX = "log4j.appender.";
  static final String      RENDERER_PREFIX = "log4j.renderer.";
  static final String      THRESHOLD_PREFIX = "log4j.threshold";
  private static final String      THROWABLE_RENDERER_PREFIX = "log4j.throwableRenderer";
  private static final String LOGGER_REF	= "logger-ref";
  private static final String ROOT_REF		= "root-ref";
  private static final String APPENDER_REF_TAG 	= "appender-ref";  
  ...
}

3、在类PropertyConfigurator 内搜索字段 ROOT_CATEGORY_PREFIX

void configureRootCategory(Properties props, LoggerRepository hierarchy) {
    String effectiveFrefix = ROOT_LOGGER_PREFIX;
    String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);

    if(value == null) {
      // ================================================================================
      value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
      effectiveFrefix = ROOT_CATEGORY_PREFIX;
      // ================================================================================
    }

    if(value == null)
      LogLog.debug("Could not find root logger information. Is this OK?");
    else {
      Logger root = hierarchy.getRootLogger();
      synchronized(root) {
	parseCategory(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
      }
    }
  }

4、查看configureRootCategory的引用,找到

public void doConfigure(Properties properties, LoggerRepository hierarchy) {
...
configureRootCategory(properties, hierarchy);
...
}
  

5、 继续网上找找到好多个 doConfigure 方法,怼不上去,换路子

第一个方法,往上没路子
static public void configure(Properties properties) {
    new PropertyConfigurator().doConfigure(properties,
					   LogManager.getLoggerRepository());
}
另外三,你一个个找上去,确实有点费劲。

三、转变思路。

1、看下上方的"一、4、直接点开 Logger.getLogger(Demo.class);"

public class Logger extends Category {
...
  static public Logger getLogger(Class clazz) {
    return LogManager.getLogger(clazz.getName());
  }
}
...

2、直接点开 LogManager 的static代码块

static{
...
       OptionConverter.selectAndConfigure(url, configuratorClassName,
					   LogManager.getLoggerRepository());
...					  
}

3、点开 selectAndConfigure 方法(上面的URL,就是第一说的 log4j.properties的路径)可以看到:

static public void selectAndConfigure(URL url, String clazz, LoggerRepository hierarchy) {
... 
   configurator.doConfigure(url, hierarchy);
}


 是不发现就对接上啦?

4、看 PropertyConfigurator 类 doConfigure 的方法:

  public void doConfigure(java.net.URL configURL, LoggerRepository hierarchy) {
  ...
  configureRootCategory(properties, hierarchy);
  ...
 }

成功对接,结束,下篇讲 log4j中各个属性如何配置进代码的,其实这篇已经讲的差不多了。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值