zoukankan      html  css  js  c++  java
  • Java日志框架——JCL

    JCL,全称为"Jakarta Commons Logging",也可称为"Apache Commons Logging"。


    一、JCL原理

    1、基本原理

    JCL这个日志框架跟Log4J,Java Logging API等日志框架不同。JCL采用了设计模式中的“适配器模式”,它对外提供统一的接口,然后在适配类中将对日志的操作委托给具体的日志框架,比如Log4J,Java Logging API等。

    在JCL中对外有两个统一的接口,分别是Log和LogFactory。

    Log的继承体系如图1:

                   图1


    LogFactory的继承体系如图2:

                                                              图2



    Log4JLogger,Jdk14Logger等是适配类。


    在Log4JLogger类中,包含有"org.apache.log4j.Logger"类,即Log4J中的Logger类,因而对Log4JLogger类中的日志操作方法的调用会被委托给"org.apache.log4j.Logger"类运行
    在Jdk14Logger类中,包含有"java.util.logging.Logger"类,即Java Logging API中的Logger类,因而对Jdk14Logger类中的日志操作方法的调用会被委托给"java.util.logging.Logger"类运行

    2、具体加载步骤

    在执行以下Java代码语句的时候,经历了哪些步骤?

    1. Log log = LogFactory.getLog(Main.class);
    2. log.error("Hello World");

    1)通过查看源代码可以发现,执行"LogFactory.getLog(Main.class)"语句的时候,最终是执行LogFactoryImp类中的discoverLogImplementation方法,在该方法中有如下代码语句:

    1. for(int i = 0; i < classesToDiscover.length && result == null; ++i)
    2. {
    3. result = this.createLogFromClass(classesToDiscover[i], logCategory, true);
    4. }

    其中classesToDiscover的值如图3所示:

                                                                                            图3



    这个过程就是依次去判断类路径中是否存在Log4J依赖,JDK依赖等。就是经常说的JCL运行时动态查找具体日志框架的过程。
    2)在1)中discoverLogImplementation方法找到具体的日志框架依赖之后,会去生成相应的适配器类实例。比如找到了Log4J日志框架依赖,那么会生成一个Log4JLogger适配器类实例(以A来表示它),并将其返回。最后该适配器类实例,被赋值给"Log log = LogFactory.getLog(Main.class)"中的log对象。
    3)执行log.error("Hello World");语句,实际上是执行A中的error(Object message)方法,而该方法中会去委托"A中所包含的org.apache.log4j.Logger类实例"进行处理。

    二、基本原理扩展

    1、本质上说,NoOpLog和SimpleLog不是适配器类,因为它们自身实现日志操作功能,而不是委托给其他日志框架。


    2、关于JCL有两个包,分别是:commons-logging:commons-logging:1.1和commons-logging:commons-logging-api:1.1
    这两者的主要差别在于前者比后者拥有更多的适配器类
    前者中的适配器体系见图1
    后者中的适配器体系见图4

                                                                   图4



    3、在commons-logging:commons-logging:1.1和commons-logging:commons-logging-api:1.1的pom.xml文件中,可以发现它们有对具体日志框架的依赖,比如在commons-logging:commons-logging:1.1的pom.xml中有如下片段:

    1. <dependency>
    2. <groupId>log4j</groupId>
    3. <artifactId>log4j</artifactId>
    4. <version>1.2.12</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>avalon-framework</groupId>
    8. <artifactId>avalon-framework</artifactId>
    9. <version>4.1.3</version>
    10. </dependency>
    即包含有对Log4J和avalon-framework(也是一个具体的日志框架)的依赖。其实想想也是如此,因为JCL中含有Log4JLogger,Jdk14Logger等适配器类,在这些适配器类中含有对对应的具体的日志框架的依赖,比如在Log4JLogger类中,有如下片段:

    1. package org.apache.commons.logging.impl;
    2. import java.io.Serializable;
    3. import org.apache.commons.logging.Log;
    4. import org.apache.log4j.Logger;
    5. import org.apache.log4j.Priority;
    6. public class Log4JLogger implements Log, Serializable {}
    以上这点表明,在项目中,我们只要包含了对commons-logging:commons-logging:1.1或者commons-logging:commons-logging-api:1.1的依赖,就会包含所有对它们所支持的具体日志框架的依赖。因而在JCL运行时动态查找具体日志框架的过程中,能够找到所有所支持的具体日志框架,根据具体的查找算法,选定某一个返回。
    但是为了更加清晰准确,我们应该还是得在项目中包含对具体日志框架的依赖比较好,比如要使用“JCL+Log4J”的组合方案,那么在项目的pom.xml中,应该包含以下片段:
    1. <dependency>
    2. <groupId>commons-logging</groupId>
    3. <artifactId>commons-logging</artifactId>
    4. <version>1.1</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>log4j</groupId>
    8. <artifactId>log4j</artifactId>
    9. <version>1.2.17</version>
    10. </dependency>

    4、在JCL中一般情况下,需要有两个配置文件,一个是JCL自身的,另外一个是具体日志框架的。比如在JCL中,具体的日志框架使用Log4J,那么需要有"commons-logging.properties"和"log4j.properties"这两个文件

    5、由上述第3点可以知道,最终使用的具体日志框架由查找算法决定,这降低了我们对日志框架使用的控制度。我们也可以通过JCL的配置文件,即"commons-logging.properties",来明确指定最终使用的具体日志框架,达到精准控制定义的目标。具体是配置文件中的"org.apache.commons.logging.Log"属性。
    比如在"commons-logging.properties"文件中,配置
    org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger

    那么显式指定使用Log4J这个具体日志框架,然后也生成"org.apache.commons.logging.impl.Log4JLogger"的一个实例


    三、JCL如何使用的具体例子

    1、JCL+Log4J

    1.1、项目中的pom.xml配置

    1. <dependencies>
    2. <dependency>
    3. <groupId>commons-logging</groupId>
    4. <artifactId>commons-logging</artifactId>
    5. <version>1.1</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>log4j</groupId>
    9. <artifactId>log4j</artifactId>
    10. <version>1.2.17</version>
    11. </dependency>
    12. </dependencies>


    1.2、commons-logging.properties和log4j.properties两个文件的内容

    "commons-logging.properties"文件内容如下:

    org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger


    "log4j.properties"文件内容如下:

    # Root logger option
    log4j.rootLogger=INFO, stdout
    

    # Direct log messages to stdout
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target=System.out
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n


    1.3、Java代码
    1. import org.apache.commons.logging.Log;
    2. import org.apache.commons.logging.LogFactory;
    3. public class Main {
    4. public static void main(String[] args) {
    5. Log log = LogFactory.getLog(Main.class);
    6. log.error("Hello World");
    7. System.out.println(log.getClass());
    8. }
    9. }

    1.4、输出结果

    如图5

                                                          图5



    2、JCL+Log4J

    2.1、项目中的pom.xml配置

    1. <dependencies>
    2. <dependency>
    3. <groupId>commons-logging</groupId>
    4. <artifactId>commons-logging</artifactId>
    5. <version>1.1</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>log4j</groupId>
    9. <artifactId>log4j</artifactId>
    10. <version>1.2.17</version>
    11. </dependency>
    12. </dependencies>


    2.2、commons-logging.properties和log4j.properties两个文件的内容

    "commons-logging.properties"文件内容如下:

    org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger


    "log4j.properties"文件不存在


    2.3、Java代码

    1. import org.apache.commons.logging.Log;
    2. import org.apache.commons.logging.LogFactory;
    3. public class Main {
    4. public static void main(String[] args) {
    5. Log log = LogFactory.getLog(Main.class);
    6. log.error("Hello World");
    7. System.out.println(log.getClass());
    8. }
    9. }

    2.4、输出结果

    如图6

                                                             图6



    3、JCL+Java Logging API

    3.1、项目中的pom.xml配置

    1. <dependency>
    2. <groupId>commons-logging</groupId>
    3. <artifactId>commons-logging</artifactId>
    4. <version>1.1</version>
    5. </dependency>
    6. <!--对JDK的依赖无需在pom.xml中配置-->

    3.2、commons-logging.propertie和logging.properties两个文件的内容

    "commons-logging.properties"文件内容如下:

    org.apache.commons.logging.Log = org.apache.commons.logging.impl.Jdk14Logger


    "logging.properties"文件是Java Logging API默认的配置文件名称,默认路径是JDK_HOME/jre/lib/logging.properties

    3.3、Java代码

    1. import org.apache.commons.logging.Log;
    2. import org.apache.commons.logging.LogFactory;
    3. public class Main {
    4. public static void main(String[] args) {
    5. Log log = LogFactory.getLog(Main.class);
    6. log.error("Hello World");
    7. System.out.println(log.getClass());
    8. }
    9. }

    3.4、输出结果

    如图7

                                                           图7



    四、其他
    1、在项目中使用JCL的好处是降低与具体日志框架的耦合,可以灵活改变使用的具体日志框架
    2、经典的日志框架组合为:JCL+Log4J

    3、Spring项目中就选用了JCL框架


    参考文献:

    [1]http://commons.apache.org/proper/commons-logging/guide.html

    [2]http://www.javapractices.com/topic/TopicAction.do?Id=143

    原文地址:https://blog.csdn.net/DSLZTX/article/details/47132329
  • 相关阅读:
    BFS visit tree
    Kth Largest Element in an Array 解答
    Merge k Sorted Lists 解答
    Median of Two Sorted Arrays 解答
    Maximal Square 解答
    Best Time to Buy and Sell Stock III 解答
    Best Time to Buy and Sell Stock II 解答
    Best Time to Buy and Sell Stock 解答
    Triangle 解答
    Unique Binary Search Trees II 解答
  • 原文地址:https://www.cnblogs.com/jpfss/p/11044229.html
Copyright © 2011-2022 走看看