Log4J学习【十六】Log4j的默认启动流程一

来源:互联网 发布:用户数据分析方法 编辑:程序博客网 时间:2024/04/30 14:42
之前已经看到了使用properties文件或者xml文件配置Log4J的方式。但是,在这两种配置方式中,我们看到,都必须要使用者在整个应用启动之前,使用代码的方式完成Log4J相应配置的读取和加载。我们已经学习了Log4j这么久了,一直会有一个疑问,为什么Log4J就必须让我们自己来配置Log4J?为什么必须让我们自己去写那一段初始化代码?原因其实很简单,在Log4J中,所有的日志总的有一个输出的方式,换句话说,必须有一个Appender。可能大部分的人会说,那么如果什么都没有配置,那直接把日志输出到Console上啊?其实不是这样的,有一些JAVA工具其实默认没有提供Console,这对我们来说可能有点不可思议,不过,还真有这样的工具。Log4J考虑到这些问题,所以没有提供默认的Logger配置。在没有任何配置的情况下,直接启动Log4j就会出现我们最开始看到的那段警告。
    既然要求我们自己来配置Log4j,那么又会出现相关的问题,不管我们采用哪种配置方式,Log4J总会要求我们在应用启动的最开始,完成Log4J的配置,所以我们不得不在一个静态类的静态代码块中完成相关的代码配置。这对程序员和Log4j框架本身的使用,都是一个不友好的设计。
考虑到这些因素,Log4J提供了一个默认初始化流程。这个默认的流程作为静态代码块注册在LogManager类中。下面结合LogManager的源代码,来看看Log4J提供的初始化流程:
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    repositorySelector = new DefaultRepositorySelector(h);

创建一个日志体系对象,并新建一个RootLogger作为这个日志体系的rootLogger,并将rootLogger的日志级别设置为DEBUG;
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
       null);

DEFAULT_INIT_OVERRIDE_KEY的值为log4j.defaultInitOverride,这句代码代表,在系统环境中找名字为log4j.defaultInitOverride的系统变量;
if(override == null || "false".equalsIgnoreCase(override)) {
如果这个系统变量没有设置值,如果有值且设置为false,则按照Log4J的默认初始化流程进行,否则就跳过初始化配置流程;
String configurationOptionStr = OptionConverter.getSystemProperty(    DEFAULT_CONFIGURATION_KEY, null);
String configuratorClassName = OptionConverter.getSystemProperty(
                                        CONFIGURATOR_CLASS_KEY, null);
URL url = null;
DEFAULT_CONFIGURATION_KEY=log4j.configuration
CONFIGURATOR_CLASS_KEY=log4j.configuratorClass

得到系统log4j.configuration和log4j.configuratorClass两个系统变量;
if (configurationOptionStr == null) {
    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    if (url == null) {
        url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    }
}
DEFAULT_XML_CONFIGURATION_FILE=log4j.xml
DEFAULT_CONFIGURATION_FILE=log4j.properties

如果没有设置log4j.configuration变量,则先尝试使用ClassPath下的log4j.xml文件,如果没有log4j.xml文件,则使用ClassPath下的log4j.properties文件。
else {
    try {
       url = new URL(configurationOptionStr);
    } catch (MalformedURLException ex) {
  // so, resource is not a URL:
  // attempt to get the resource from the class path
       url = Loader.getResource(configurationOptionStr); 
    }
}
如果设置了log4j.configuration环境变量,则直接使用log4j.configuration环境变量指定的配置文件来加载配置。
if(url != null) {
LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
    try {
        OptionConverter.selectAndConfigure(url, configuratorClassName,     LogManager.getLoggerRepository());
    } catch (NoClassDefFoundError e) {
        LogLog.warn("Error during default initialization", e);
    }
    } else {
    LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
}

    经过前面的配置,如果最终找到一个配置文件,则根据配置文件的类型XML或properties选择指定的DOMConfigurator来完成配置,如果配置文件是properties,则使用PropertyConfigurator来完成配置。另外,如果环境变量log4j.configuratorClass设置了一个确定的配置文件类型,则使用给定的Configurator对象来完成配置。
    

有了Log4J提供的初始化流程,我们就可以直接使用Log4j,而不需要再提供自己的初始化代码了:
@Test
public void testXmlConf() {
    Logger log = Logger.getLogger("cd.itcast.log");
    log.debug("log debug..");
    log.info("log info..");
}

在这段测试代码中,我们删除了所有的初始化方法,直接使用Logger完成日志。在classpath下,我们提供两个配置文件,一个XML,一个properties:
log4j.properties:
log4j.rootLogger=INFO,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.xml:
<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration>
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="conversionPattern" value="%r [%t] %p %c %x - %m%n"/>
        </layout>
    </appender>
    <logger name="cd.itcast.log">
        <level value="DEBUG" />
        <appender-ref ref="console"/>
    </logger>
</log4j:configuration>

可以看到,在properties文件中,我们使用simpleLayout输出日志级别INFO;在xml文件中,我们使用patternLayout输出日志级别DEBUG。我们运行测试,控制台输出:
0 [main] DEBUG cd.itcast.log  - log debug..
0 [main] INFO cd.itcast.log  - log info..
可以看到,这时候,log4j.xml起了作用。如果删除log4j.xml,再次运行:
INFO - log info..
可以看到,这个时候,log4j.properties起了作用。
上面的所有的应用,都是在application方式下的测试。
0 0