Apache Log4j 架构之初始化

作者:聂勇 欢迎转载,请保留作者信息并说明文章来源!

前面介绍了Log4j的总体架构,这篇文章接着介绍Log4j的初始化。

Log4j初始化 | Log4j Initialization

下面分三个步骤来介绍Log4j的初始化:

1、getLogger(String)

在代码中我们以如下的代码来使用Log4j。

1
private Logger _logger = Logger.getLogger(Hello.class);

在执行Logger.getLogger(Class)方法,在Log4j内部会执行一系列方法。其执行序列图如下所示:
getLogger

2、LogManager初始化

如果是第一次调用LogManager,这时Log4j会读取配置文件并对自身初始化。其执行序列图如下:
LogManager初始化

其中:
1)Hierarchy 实现了 LoggerRepository 接口。
2)RootLogger 实现了 Logger 接口。
3)DefaultRepositorySelector 实现了 RepositorySelector 接口。
4)getSystemProperty(String key, String def)) 这一步骤中获取系统变量 log4j.defaultInitOverride、log4j.configuration、log4j.configuratorClass 的值。log4j已经不推荐设置这些系统变量。
5)getResource(String) 这一步骤中获取 log4j.xml、log4j.properties 配置文件。首先获取log4j.xml,然后再获取log4j.properties,如果在log4j.xml 和 log4j.properties 都获取失败的情况下会用 log4j.configuration 来代替(如果log4j.configration存在的话)。
6)selectAndConfigure 这一步骤中,如果class 为空,并且 url 指向的文件名后缀为 xml,则将class设置为“org.apache.log4j.xml.DOMConfigurator”,否则新建一个“org.apache.log4j.PropertyConfigurator”的实例。

3、解析配置文件

获得一个Configurator实例后,调用它的 doConfigure(Url url, LoggerRepository repository)方法传入配置文件完事路径,然后解析配置文件内容。
下面以 log4j.xml 为例来介绍配置文件的解析过程:
解析配置文件

1)在执行 doConfigure(ParseAction action, LoggerRepository repository) 方法时,会通过获取系统的环境变量 javax.xml.parsers.DocumentBuilderFactory 获得XML的Document解析器对配置文件log4j.xml进行解析。
2)parse(Element element)的关键代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
String tagName = null;
Element currentElement = null;
Node currentNode = null;
NodeList children = element.getChildNodes();
final int length = children.getLength();
for (int loop = 0; loop < length; loop++) {
currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
currentElement = (Element) currentNode;
tagName = currentElement.getTagName();
if (tagName.equals(CATEGORY_FACTORY_TAG)
|| tagName.equals(LOGGER_FACTORY_TAG)) {
parseCategoryFactory(currentElement);
}
}
}
for (int loop = 0; loop < length; loop++) {
currentNode = children.item(loop);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
currentElement = (Element) currentNode;
tagName = currentElement.getTagName();
if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) {
parseCategory(currentElement);
} else if (tagName.equals(ROOT_TAG)) {
parseRoot(currentElement);
} else if (tagName.equals(RENDERER_TAG)) {
parseRenderer(currentElement);
} else if (tagName.equals(THROWABLE_RENDERER_TAG)) {
if (repository instanceof ThrowableRendererSupport) {
ThrowableRenderer tr = parseThrowableRenderer(currentElement);
if (tr != null) {
((ThrowableRendererSupport) repository)
.setThrowableRenderer(tr);
}
}
} else if (!(tagName.equals(APPENDER_TAG)
|| tagName.equals(CATEGORY_FACTORY_TAG) || tagName
.equals(LOGGER_FACTORY_TAG))) {
quietParseUnrecognizedElement(repository, currentElement,
props);
}
}
}

1、获取根元素的 tagName。
1)如果 tagName 不是 log4j:configuration 并且 不是已经不推荐的 configuration,输出错误信息。
2)如果 tagName 不是 log4j:configuration 是已经不推荐的 configuration,输出警告信息。

2、获取根元素的 debug 属性。
1)如果 debug 属性的值不等于””且不等于”null”,调用 LogLog.setInternalDebugging(boolean),否则输出调试信息。

3、获取根元素的 reset 属性。
1)如果 reset 属性的值 不等于””且等于”true”,调用 repository.resetConfiguration()。

4、获取根元素的 threshold 属性。
1)如果 threshold 属性不等于””且不等于”null”,调用 repository.setThreshold(String)。

5、循环处理根元素的所有子元素。
1)如果子元素是 categoryFactory 或 loggerFactory,则调用内部方法 parseCategoryFactory(Element factoryElement) 处理;

6、再次循环处理根元素的所有子元素。
1)如果子元素是 category 或 logger,调用内部方法 parseCategory(Element loggerElement) 处理。
2)如果子元素是 root,调用内部方法 parseRoot(Element rootElement) 处理。
3)如果子元素是 renderer,调用内部方法 parseRenderer(Element rootElement) 处理。
4)如果子元素是 throwableRenderer 并且repository instanceof ThrowableRendererSupport,调用内部方法 parseThrowableRenderer(Element rootElement) 处理返回一个ThrowableRenderer,如果没有返回null,调用((ThrowableRendererSupport) repository).setThrowableRenderer(ThrowableRenderer)。
5)如果子元素是 appender 或者 categoryFactory 或者 loggerFactory,调用内部方法 quietParseUnrecognizedElement(Object instance, Element element, Properties props) 处理。

相关文章 | Index

1、Apache Log4j 架构
2、Apache Log4j 架构之初始化
3、Apache Log4j 架构之输出日志