问: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中各个属性如何配置进代码的,其实这篇已经讲的差不多了。