先看一張圖:html
是否是有點暈, 暈就對了。這個僅僅是 slf4j 的狀況,實際上, 咱們不只要接觸到 slf4j ,有時候還會接觸其餘的日誌系統。且看下文分解。java
最開始的時候, 咱們都是使用log4j, 怎麼使用呢? 先引入jar,log4j-1.x.x jarapache
maven是這樣的:api
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
而後配置: 配置文件主要是 log4j.properties, 具體略app
而後代碼中使用框架
static org.apache.log4j.Logger logger = org.apache.log4j.LogManager.getLogger(TestLog.class);
有時候咱們也使用Apache的 commons-logging ,也就是 Jakarta Commons Logging,簡稱 JCL。commons-logging其實也是一個日誌 接口,不是一個日誌控件,沒有日誌功能,它只是統一了JDK Logging與Log4j的API,並把日誌功能交給JDK Loggings或者是log4j 。maven
commons-logging可以選擇使用Log4j仍是JDK Logging,可是他不依賴Log4j,JDK Logging的API。若是項目的classpath中包含了log4j的類庫,就會使用log4j,不然就使用JDK Logging。使用commons-logging可以靈活的選擇使用那些日誌方式,並且不須要修改源代碼。spa
怎麼使用呢? 首先須要一個 commons-logging-1.2.jar, 而後引入 log4j的類庫,或者不引入直接JDK Logging(這裏的 log4j的類庫 應該是 指log4j-1.x , 對於 log4j2 不知道是否支持 ).net
參考 :https://blog.csdn.net/u011794238/article/details/50747953 日誌
maven是這樣的:
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
配置:主要是 commons-logging.properties,具體略
關於 commons-logging ,其實也是一個 slf4j 相似的日誌接口系統,至於其原理,請參考其餘的博客,
後面出了個log4j2,log4j2是怎麼使用的? 仍是先引入jar : log4j-api-2.x.x.jar和log4j-core-2.x.x.jar
maven是這樣的:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
沒錯,引入一個 log4j-core 便可, log4j-core 會自動引入 log4j-api,另外我發現這麼一個jar:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j</artifactId> <version>2.8.2</version> </dependency>
仔細看一下,這個僅僅是一個pom 不是jar,也就是 log4j-core 的parent 。
而後配置: 配置文件主要是 log4j2.xml ( 有時候也能夠是 log4j.xml, 或其餘名字 ), 具體略
而後代碼中使用
static org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger(TestLog.class);
注意看到 log4j 、log4j2 的差異仍是比較大的, log4j須要一個 jar,log4j-1.x.x jar ,並且是 1.x.x 的格式, 最高好像也就是1.7.25 , 我是沒有看到 log4j-2.x的 jar 的。 可是到了 log4j2,jar 的命名發生了很大的變化: log4j-api-2.x.x.jar和log4j-core-2.x.x.jar ,沒有 log4j-2.x .jar , 並且也不是一個jar ,是分開了2個。
後面又來了一個 logback, logback 是天生就和slf 緊密結合在一塊兒的,沒法分開。(觀察發現logback也沒有提供任何的 Logger 實現,logback-core 的功能主要就是實現了很大的 appender ,pattern 等)通常咱們須要引入logback-classic , 它直接依賴了 logback-core、slf4j-api , 因此,咱們須要3個jar 。
maven是這樣的:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
而後配置: 配置文件主要是 logback.xml , 具體略
而後代碼中使用,(只能經過slf4j 的api )
static Logger logger = LoggerFactory.getLogger(TestLog.class);
直接用 jul 的人應該不多了吧。不過這裏仍是要說明一下。具體 怎麼使用呢?首先,它是jdk 自帶的,不須要引入jar:
而後配置: 默認配置文件是logging.properties,logging.properties 通常位於 jdk或者jre 的lib 目錄, 一個 jdk或者jre 只有一個配置。具體略
而後代碼中使用
static java.util.logging.Logger logger = java.util.logging.Logger.getLogger(TestLog.class.getName());
logger.info("in");
logger.severe("severe");
logger.fine("fine");
能夠看到它的 Logger 是 java.util.logging 包(簡稱 JUL)下面的, 是jdk 自帶的。 不過須要注意的是 JUL的Logger 提供的方法和其餘的框架的還不同。
它的日誌是這樣的:
四月 11, 2019 1:52:46 下午 com.lk.TestLog main 信息: in 四月 11, 2019 1:52:46 下午 com.lk.TestLog main 嚴重: severe
能夠看到其中的月份和 日誌級別都使用了 漢字, 很是的明顯的 特徵。
前面都是直接使用的方式(除了logback), 若是咱們統一到 slf4j 呢?這裏說的是統一到 slf4j是指 代碼中使用 slf4j的API。 首先咱們要明白,slf4j 是什麼? 它是一個統一的日誌接口框架,這樣說可能仍是有些懵逼。 怎麼說呢, 能夠簡單理解爲它提供了幾個關鍵的接口,可是沒有實現他們。 因此說它只是一個 日誌接口。一般咱們須要 slf4j 結合其餘日誌框架來打印咱們的日誌。 老實說,這樣作TM有些奇特, 這樣作的主要目的是 方便的替換 咱們日誌框架的實現, 而不用修改代碼—— 其實這樣的需求也是很是少的。
無論怎麼說,slf4j 已然成爲了主流。
幾乎全部的其餘日誌框架均可以做爲 slf4j 日誌接口的實現。怎麼使用呢? 一般咱們須要首先引入 slf4j-api-1.x.x.jar ( 目前來看, 主要有 1.5,1.6,1.7 三個實現,1.5 有些特別, 兼容性不是很好), 而後引入具體的實現的 jar。
有哪些實現?
NOP, 也就是No Operation,也就是不作任何操做。不須要引入任何其餘jar,配置文件也是無。
logback,前文已述
simple,意味着簡單。它很是簡單的實現, 須要引入slf4j-simple-1.7.5.jar,
maven是這樣的:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.12</version> </dependency>
slf4j-simple 依賴了 slf4j-api 。slf4j-simple 一般只是把日誌直接打印到 控制檯。
配置是:simplelogger.properties 或者經過D系統參數。
其實就是把日誌操做 轉接給了 jdk , 也就是 jul , 須要 slf4j-jdk14-1.x.x.jar ,
maven是這樣的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.25</version>
</dependency>
slf4j-jdk14 依賴了 slf4j-api 。
配置同直接使用JUL的場景
具體日誌工做交給了 log4j , 須要 slf4j-log4j12-1.x.x.jar (主要是 slf4j-log4j12-1.6.x.jar, slf4j-log4j12-1.7.x.jar), log4j-1.2.x.jar ,
maven是這樣的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
slf4j-log4j12 依賴了slf4j-api 和 log4j12 。
配置同直接使用log4j的場景
依賴 log4j2 , 須要 log4j-slf4j-impl-2.x.x.jar , log4j-api , log4j-core ,
maven是這樣的:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.8.2</version>
</dependency>
log4j-slf4j-impl 依賴了slf4j-api 和 log4j-api, 可是並無依賴 log4j-core , 所以, 咱們須要手動引入 它 。
配置同直接使用log4j2的場景
依賴 commons-logging , 須要 slf4j-jcl ,
maven :用得少,略
配置:略
變態的還不只僅是這個, 有時候,咱們還須要 反向的 日誌操做。好比 咱們有代碼已經直接使用的 log4j 的api, 可是想使用 slf4j 的實現,怎麼辦呢? 能夠 先引入 log4j 的api的jar, 而後引入 slf4j-api , 而後引入 slf4j 的具體實現(如上), 好比 log4j 的接口,slf4j 作橋接, logback 的實現, 這個是徹底能夠的。 (這能夠達到一種奇特的效果, 整個系統中, 雖然有各類第二方、三方框架, 他們直接使用各類各樣的 日誌api, 可是我均可以讓他們 統一使用 logback的實現, 也就是 只使用一個 配置便可: logback.xml , 能夠減小配置量)
可是, 咱們確定不會說, log4j 的接口,slf4j 作橋接, 而後又採用 log4j 做爲slf4j 的實現。看起來行得通, 實際上會出現 循環引用的問題,
這種作法,其實有點繞,容易讓人迷糊。也許是我見識短淺,我其實沒有直接使用過這樣作法。 不過, 如今中 確實也有這樣的需求。
具體來講 也有不少種, log4j, log4j2, jcl,jul,等等。可是 咱們彷佛找不到 logback 橋接給 slf4j 的狀況,我感受是由於logback 沒有直接使用的接口,它天生就是和slf4j 緊密聯繫的。
對於 log4j, 咱們首先須要log4j的 api接口: log4j-over-slf4j-1.7.x.jar, 其餘的就交給了 slf4j ———— 你可能有疑問, log4j 的接口在哪裏呢? 沒錯,就是 log4j-over-slf4j-1.7.x.jar ,這裏咱們沒有使用 log4j-1.x.x jar,由於 log4j-1.x.x jar 包含了 log4j 的實現,咱們不須要它,咱們須要排除它。 這種作法簡直難以想象, 不過它就是這麼發生了!
maven是這樣的:
<dependency> <groupId>org.slf4j</groupId> <version>1.7.21</version> <artifactId>log4j-over-slf4j</artifactId> </dependency>
log4j-over-slf4j 依賴了slf4j-api。
至於橋接到slf4j 以後的工做,好比配置文件啊,還須要的其餘jar 啊,請參考前文。總之, 不要出現了 循環引用便可。
另外,我注意到, 若是 log4j-over-slf4j 、 log4j-1.x.x jar 若是同時存在於 maven 的pom ,或者classpath, 那麼 究竟是啓用哪個呢? 對應 maven, 答案是, 哪一個先出如今pom中 就啓用哪個!
須要重要的是: log4j-over-slf4j.jar 不能和 slf4j-log4j12.jar 同時存在於 classpath 中, 不然
對於 slf4j-log4j12-1.7.25.jar :出現
Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError.
slf4j-log4j12-1.7.25.jar 比較溫和,有檢測機制, slf4j-log4j12-1.7.25.jar 以前的 slf4j-log4j12-1.x.x jar 則是直接拋出 異常:
java.lang.StackOverflowError at java.util.HashMap.hash(HashMap.java:338) at java.util.HashMap.get(HashMap.java:556) at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:67) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:358) at org.apache.log4j.Category.<init>(Category.java:57) at org.apache.log4j.Logger.<init>(Logger.java:37) at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:43) at org.apache.log4j.LogManager.getLogger(LogManager.java:45)
除了log4j, 我想其餘日誌框架也是如此,不能出現over-slf4j 以後出現循環委託的狀況。
log4j 是 1.x 時代了, 若是是 log4j2 呢? 咱們首先須要log4j2的 api接口:log4j-to-slf4j-2.x.x.jar,
maven是這樣的:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.11.1</version>
</dependency>
log4j-to-slf4j-2.x.x.jar 依賴了slf4j-api 和log4j-api ( log4j-api 是log4j2 的api 接口 ), log4j-to-slf4j-2.x.x.jar 沒有依賴 log4j-core。 那麼 log4j2 是怎麼反向橋接到 slf4j 上去的呢? 其實這個是 log4j-to-slf4j 的功勞,log4j-to-slf4j-2.x.x.jar 橋接了 log4j-api ,而後具體實現交給了 slf4j。
特別注意到:log4j-1.x 的橋接jar 名是這樣的: log4j-over-slf4j 而log4j-2.x 的橋接jar 名是這樣的: log4j-to-slf4j, 名字很是相近。
至於橋接到slf4j 以後的工做,請參考前文。
前面說過使用 SLF4J的API, 而後 使用JCL的實現, 反過來也是能夠的。
jcl 並非jul, 不是 java.util.logging 而是 org.apache.commons.logging , 也就是 commons-logging 的那一套。 爲此, 咱們須要一個 jcl-over-slf4j-1.x.x.jar
maven是這樣的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
至於橋接到slf4j 以後的工做,請參考前文。
JUL 和 JCL 是僅僅一字之別,可是千萬不能搞混啊!它是將 jdk logging API 打印的日誌交給了 slf4j,咱們 須要一個 jul-to-slf4j-1.7.x.jar
maven是這樣的:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
代碼中還須要作一些修改:
須要先執行下面的:
static{ SLF4JBridgeHandler.install(); }
不過從打印的結果, 我看到 日誌打印了兩次, 彷佛哪裏出了問題,並無達到想要的效果。
四月 11, 2019 6:40:12 下午 com.lk.TestLog main 信息: in 18:40:12,318 [com.lk.TestLog] - severe --- log4j的日誌
四月 11, 2019 6:40:12 下午 com.lk.TestLog main 嚴重: severe
須要注意的是 咱們並無 jul-over-slf4j 的jar, 這個多是命名的歷史緣由, 暫時 jul-to-slf4j 能夠理解爲就是 jul-over-slf4j ...
至於橋接到slf4j 以後的工做,請參考前文。
這樣的需求也是有的,作法確定也是有的,也確定有人實現了的。好比,貌似 feign 也有一個實現,gossip 也有:
這些jar我沒有用過,具體,就很少說了。
關於SLF4J 其實也能夠寫不少,還有JCL( 也就是commons-logging)具體的原理這裏很少講了,請參考其餘的博客。總之,感受這整個java 的日誌系統 仍是挺麻煩的,特別是其中的jar的命名,不太規律,容易混淆,不容易記住。搞來搞去, 容易把人搞暈呢,這個時候 就須要看其源碼! 其實其中不少jar 的實現是很簡單的,也就幾個類,特別是那些橋接的jar, 一打開看一下就明白了,哦,說得也是呢!
看個人文章後是否是有所收穫呢?是否是應該點32個贊鼓勵一下呢?
參考:
https://my.oschina.net/pingpangkuangmo/blog/410224https://www.slf4j.org/legacy.htmlhttps://blog.csdn.net/u011794238/article/details/50747953https://blog.csdn.net/john1337/article/details/76152906http://www.cnblogs.com/chen310/p/4216316.htmlhttps://blog.csdn.net/u011794238/article/details/50783188https://blog.csdn.net/u011794238/article/details/50771488