Apache Log4j 架构之一 初始化

来源:互联网 发布:淘宝网全屏轮播代码 编辑:程序博客网 时间:2024/05/19 07:07

转载地址:http://aofengblog.blog.163.com/blog/static/631702120114674444644/


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

Log4j初始化 | Log4j Initialization

下面分三个步骤来介绍Log4j的初始化:
1、getLogger(String)。
在代码中我们以如下的代码来使用Log4j。
private Logger _logger = Logger.getLogger(Hello.class);

在执行Logger.getLogger(Class)方法,在Log4j内部会执行一系列方法。其执行序列图如下所示:
Apache Log4j 架构之初始化 | Apache Log4j Architecture Level 2:Initialization - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
  

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

Apache Log4j 架构之初始化 | Apache Log4j Architecture Level 2:Initialization - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
 
其中:
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 为例来介绍配置文件的解析过程:
Apache Log4j 架构之初始化 | Apache Log4j Architecture Level 2:Initialization - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
1)在执行 doConfigure(ParseAction action, LoggerRepository repository) 方法时,会通过获取系统的环境变量 javax.xml.parsers.DocumentBuilderFactory 获得XML的Document解析器对配置文件log4j.xml进行解析。
2)parse(Element element)的关键代码如下。
  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 = (ElementcurrentNode;
        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 = (ElementcurrentNode;
        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) {
              ((ThrowableRendererSupportrepository)
                  .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) 处理。


0 0