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代码语句的时候,经历了哪些步骤?

[java]  view plain  copy
  1. Log log = LogFactory.getLog(Main.class);  
  2. log.error("Hello World");  

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

[java]  view plain  copy
  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中有如下片段:

[html]  view plain  copy
  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类中,有如下片段:

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

[html]  view plain  copy
  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"文件内容如下:

[plain]  view plain  copy
  1. org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger  


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

[plain]  view plain  copy
  1. # Root logger option  
  2. log4j.rootLogger=INFO, stdout  
  3.    
  4. # Direct log messages to stdout  
  5. log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
  6. log4j.appender.stdout.Target=System.out  
  7. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
  8. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n  


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

1.4、输出结果

如图5

                                                      图5



2、JCL+Log4J

2.1、项目中的pom.xml配置

[html]  view plain  copy
  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"文件内容如下:

[plain]  view plain  copy
  1. org.apache.commons.logging.Log = org.apache.commons.logging.impl.Log4JLogger  


"log4j.properties"文件不存在


2.3、Java代码

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

2.4、输出结果

如图6

                                                         图6



3、JCL+Java Logging API

3.1、项目中的pom.xml配置

[html]  view plain  copy
  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"文件内容如下:

[plain]  view plain  copy
  1. 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代码

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

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



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值