1 log4j
log4j是使用得最廣泛的日誌系統,log4j對日誌系統抽象出logger,logger工廠,appender,日誌級別,日誌格式等核心概念。這幾個概念被廣泛借鑑於其他日誌系統的設計,經久不衰。
它的核心類圖如下:
在上圖中最重要的一個類是Logger,客戶直接調用這個類打出各種級別的日誌。logger是一個層級結構,可能有父logger和子logger,這種層級關係的意義在於可以使子logger繼承父logger的某些屬性,或者可以讓父logger的日誌信息涵蓋子logger。
logger組合了一個AppenderAttachableImpl,AppenderAttachableImpl聚合了一組appender(即日誌輸出源)。appender的日誌級別、日誌文件路徑、日誌文件行爲、日誌格式都可以通過log4j.xml文件配置。
2 simple log facade for java(SLF4J)
在java的開源體系內,除了log4j之外,還有很多其他的日誌系統如jdk自帶的util包裏的logging、logback(log4j的作者吸取了log4j的經驗,最新開發出來的另一個日誌系統,據說性能更優越)等。
爲了方便應用能夠在不改變代碼的前提下靈活改變日誌系統的實現,比如想從log4j遷移到logback裏,SLF4J對所有日誌系統進行更高層次的抽象,爲不同的日誌系統提供了統一的門面,客戶代碼只需要和SLF4J打交道,調用門面統一接口就能做到和具體的日誌系統解耦,可以在部署時切換不同的日誌系統實現。
客戶調用LoggerFactory.getLogger,SLF4J會查找classpath,根據classpath中引用的日誌jar包決定和哪種具體的日誌系統進行綁定。
- package com.longji;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.junit.Test;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class LogTest extends BaseTestCase {
- @Test
- public void testSLF() {
- Logger logger = LoggerFactory.getLogger("1");
- logger.error("testSLF");
- }
- }
綁定規則參考下圖
3 commons-logging(JCL)
JCL的目的和SLF4J的目標是類似的,也是爲了對不同的日誌系統實現進行統一抽象,讓客戶代碼和具體的日誌系統解耦。
示例:
客戶調用LogFactory.getLog,JCL根據特定的查找規則拿到LogFactory實例,創建具體的logger對象。
它的查找規則是(參考http://spiritfrog.iteye.com/blog/391685)
a. 從系統屬性中查找鍵爲 org.apache.commons.logging.LogFactory 的值作爲 LogFactory 的實現類;卻通過 System.getProperty("org.apache.commons.logging.LogFactory") 獲得
b. 使用 JDK1.3 jar 的 Service Provider Interface(SPI) 類發現機制,從配置文件 META-INF/services/org.apache.commons.logging.LogFactory 的的第一行讀取 LogFactory 的實現類名。這個 META-INF/services/org.apache.commons.logging.LogFactory
文件可以是某個 Web 應用的根目錄中;也可以在 classpath 下,如某個 Jar 包中,WebRoot/WEB-INF/classes 中等。這裏需多加留心下 META-INF/services/org.apache.commons.logging.LogFactory 這個目錄層次及文件名。
c. 在 Classpath 下的 commons-logging.properties 文件中的,找到 org.apache.commons.logging.LogFactory 屬性值作爲 LogFactory 實現類
d. 前面三步未找個 LogFactory 的實現類,或有任何異常的情況下,就用默認的實現類,即 LogFactory 爲我們準備的 org.apache.commons.logging.impl.LogFactoryImpl
- package com.longji;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.junit.Test;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class LogTest extends BaseTestCase {
- @Test
- public void testJCL() {
- Log logger = LogFactory.getLog("2");
- logger.error("testJCL");
- }
- }
4 集大成者SLF4J
JCL和SLF4J的功能類似,如果想要將JCL項目平滑遷移到SLF4J,SLF4J提供瞭解決方案,將org.apache.commons.logging.LogFactory.getLog()委派到SLF4J自身的factory中。
這種平滑遷移的技術是通過利用org.apache.commons.logging.LogFactory.getLog()的 Service Provider Interface(SPI) 查找規則實現的,需要在項目中引入jcl-over-slf4j.jar,jar包裏的/META-INF/services/org.apache.commons.logging.LogFactory把LogFactory的具體實現指向org.apache.commons.logging.impl.SLF4JLogFactory,再由SLF4JLogFactory按照SLF4J自己的規則去綁定具體的日誌系統。
(參考http://hi.baidu.com/tmser/item/15e5f0e9639ebcc3bbf37dd5,http://www.360doc.com/content/10/0908/15/1542811_52121394.shtml)
pom依賴參考
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.0.6</version>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>1.0.6</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.6.6</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-jdk14</artifactId>
- <version>1.6.6</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.6.6</version>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- <version>1.6.6</version>
- </dependency>