java的日志知識


java常用的日志有以下幾種 :

一、jdk自帶的java.util.logging包下的日志功能, 不常用。

 

 

二、commons-logging  + log4j 的搭配 。log4j是日志功能的具體實現,而commons-logging則是日志接口的聲明,它的出現也是為了解決應用和具體的日志框架解耦合的問題,它采用的是運行時動態綁定的方式來決定使用哪個日志框架。 什么是動態綁定 ?參考commons-logging-1.1.3的org.apache.commons.logging.LogFactory類的方法: 

public static Log getLog(Class clazz) throws LogConfigurationException {
  return getFactory().getInstance(clazz);
}

關鍵在getFactory()返回的LogFactory(日志工廠) 是什么 !

我們進一步看獲取日志工廠的方法:

public static LogFactory getFactory() throws LogConfigurationException

從419-646行:代碼比較長不列出,闡述如下: 

1、獲取線程上下文ClassLoader(默認是加載應用的ClassLoader)。 

2、看線程上下文ClassLoader是否有緩存的LogFactory,有就直接返回LogFactory  。

3、找classpath下面的commons-logging.properties ,如果use_tccl屬性為false,則不使用Thread ContextClassLoader .默認use_tccl 為true ;.

4、找是否有org.apache.commons.logging.LogFactory 這個系統配置項,利用Thread ContextClassLoader 加載org.apache.commons.logging.LogFactory ,並創建一個LogFactory實例(在后面要描述的jcl-over-slf4j包和commons-logging包里面都有這個類。) 

5、如果還找不到,則找包含了META-INF/services/org.apache.commons.logging.LogFactory 這個文件的Jar包,找到了就用這個文件里面的LogFactory類名創建LogFactory實例

6、如果還找不到,則找commons-logging.properties 文件,利用屬性文件里面的org.apache.commons.logging.LogFactory 屬性獲取LogFactory類並創建LogFactory實例。

7、還找不到,則找org.apache.commons.logging.impl.LogFactoryImpl 這個類 創建實例。

8、創建好LogFactory實例以后,會

cacheFactory(contextClassLoader, factory); 

把LogFactory對象和線程上下文ClassLoader在map中關聯起來,加速LogFactory對象的獲取。

 

從以上的分析來看,我們假設一種簡單的場景, 

沒有org.apache.commons.logging.LogFactory 這個系統配置項,classpath下沒有包含META-INF/services/org.apache.commons.logging.LogFactory 這個文件的Jar包、沒有commons-logging.properties 文件,只有commons-logging和Log4j的jar .

 

此時會使用org.apache.commons.logging.impl.LogFactoryImpl 這個類(在commons-logging的jar 包里面) 來創建Log實例,而LogFactoryImpl在獲取Log類的時候,會參照下面一個順序: 

private static final String[] classesToDiscover = {
LOGGING_IMPL_LOG4J_LOGGER,
"org.apache.commons.logging.impl.Jdk14Logger",
"org.apache.commons.logging.impl.Jdk13LumberjackLogger",
"org.apache.commons.logging.impl.SimpleLog"
};

來使用某一個日志器, 可以看到默認就是使用log4j日志的。 

至此,我們弄清了commons-logging的動態綁定機制。 

但是這種機制的問題在哪兒呢,由於它使用了ClassLoader尋找和載入底層的日志庫, 導致了象OSGI這樣的框架無法正常工作,因為OSGI的不同的插件使用自己的ClassLoader。 OSGI的這種機制保證了插件互相獨立,然而卻使Apache Common-Logging無法工作。

 

 

 

 

三、slf4j + logback的搭配. 

slf4j和logback是同一個人開發的,所以不像slf4j + log4j搭配使用時,還需要加上一個所謂的適配器jar包(比如:slf4j-log4j.jar,適配器包的作用就是通過class composition的適配方式把log4j的日志轉換成slf4j的接口)。

和commons-logging在運行時確定日志框架不同,slf4j采用的方式是在編譯時靜態綁定真正的log庫, 它的原理是:

   (1)用ClassLoader找包含了org.slf4j.impl.StaticLoggerBinder類的Jar包,這個Jar就包含在logback-classic.jar、slf4j-log4j等包里面 ,因此,如果在classpath下面

同時包含了這些jar的話, 程序將會出現一個警告,提示classpath下面有多個slf4j的綁定 。這也是我們在使用slf4j日志時需要注意的問題,不過slf4j並不會報錯, 而是選擇一個

jar中的StaticLoggerBinder,所以在使用的時候要特別注意不能同時包含logback-classic 、 slf4j-log4j、slf4j-jdk等橋接包 。

我們假設使用的是logback做日志框架 ,這時會拿到logback-classic.jar里面的org.slf4j.impl.StaticLoggerBinder ,這個StaticLoggerBinder獲取到日志工廠以后,

利用日志工廠獲取到ch.qos.logback.classic.Logger, 接下來使用的就是logback的日志了。

 

而如果是classpath下面包含的是slf4j-log4j這個橋接包, 那么拿到的就是Log4j的LogFactory,從而也就用到了log4j的日志。

 

 

 

 

 四、既然slf4j的靜態綁定方式解決了commons-logging動態綁定方式在運行時可能拿不到日志接口實現類的問題,而且號稱效率比log4j要更好(為什么更好,后續還會深入分析) 那直接都換成slf4j+logback的日志方式不就行了么,但現實是很多的應用之前都是建立在commons-logging+log4j的日志方式上的,有什么辦法不改動應用的代碼,達到commons-logging日志轉到slf4j的目的么?把commons-logging.jar替換掉就好了,看下圖:

具體的原理是什么呢? 以LogFactory.getLog("loggerName")為例:

1、org.apache.commons.logging.LogFactory類被jcl-over-slf4j包里面的同包同名類替換掉了。

2、獲取到的日志工廠是一個SLF4jLogFactory ,這個日志工廠在獲取org.apache.commons.logging.Log 實例的時候,先基於前面描述的slf4j靜態綁定機制,拿到了一個org.slf4j.Logger,然后用一個適配器類做接口轉換,把slf4j的日志轉換成commons-logging的日志器。 

 

 

總結下來,我們有以下幾點啟發:

1、適配器模式可以幫助我們做各種接口包的無縫集成。

2、復雜的java應用還是在classloader機制上做文章,即使是slf4j的靜態綁定機制 ,其實也是在編譯時檢查了classpath下是否有多個jar包包含StaticLoggerBinder類,

真正運行的時候由線程上下文的classloader(默認是app classloader)來加載這個StaticLoggerBinder類而已。

3、要分清Java日志系統里面各種包的作用: 

 1)日志接口包:commons-logging , slf4j-api 

 2) 日志框架包:log4j, logback, 

 3)  日志適配器包:slf4j-log4j,slf4j-jdk 

 4)  把某一個日志接口轉換到另一個日志接口的橋接包:jcl-over-slf4j,log4j-over-slf4j 等。

 

 

 

 


免責聲明!

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



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