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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM