一切事情的發展都是有緣由的,java的日志為啥會發展成現在這個樣子,我們來梳理下java日志的發展過程。 我們在項目中經常會遇到jar包沖突,而且看起來包名都差不多,既頭大又懵逼,網上隨便一搜,各種關系圖看的更暈了,都是些啥玩意兒。

索性干脆把日志型痛理清楚,我們現在學習技術,好的地方是技術一般都比較成熟,比較多的坑都被人踩過了,解決方案也比較多,但是不好的地方就是,由於容易使用,追求效率的同時就忽略了技術本身,為什么有這項技術,為了解決什么問題,原理是什么。
言歸正傳,一件事情很難梳理清楚,那么當你從根上把這件事的來龍去脈梳理清楚了,這件事情也就沒有那么難以理解了。
最初是沒有我們使用的這些日志技術的,最開始的日志打印方式
System.out System.err
這應該是最早的日志記錄方式,不靈活不可配置,要么全部打印要么不要打印,沒有日志級別的管理。
log4j
log4j的出現可以追溯到1996年,1996年初,豆粥安全電子市場(E.U.SEMPER)項目決定編寫自己的項目跟蹤API,這個API就是后來大名鼎鼎的log4j,log4j已經推出就異常火爆,提到log4j就不得不提其主要貢獻者,ceki gulcu,后來log4j成了apache基金會的一員,讓log4j一度稱為了業界的日志標桿,apache據說建議sun把log4j引入到java的jdk中,后來sun拒絕了,並采納了這個建議,自己出了一個日志庫。
jul(java util logging)
sun在2002年2月推出了java 1.4發布,sun竟然推出了自己的日志庫java utillogging,其實很多日志思想也都仿照log4j,畢竟log4j已經比較成熟了,顯然log4j更加成熟。
JCL(Jakarta Commons Logging)
apache針對剛出來的jul,有搞了一套jcl,打算一統日志江湖,指定日志標准,jcl是日志抽象層,默認有一個Simple log的實現,(就像jdbc一統數據訪問層),讓日志產品去實現它的抽象,只要你的日志代碼依賴JCL接口就可以很方便的在Log4j和JUL之間切換,畫個圖展示線關系大概是這樣的:
但是好景不長,隨着JCL的應用,人們發現jcl帶來的問題比它解決的問題還要多,適逢亂世,出來解決這個問題的應用問世了。
這個時候Slf4j應運而生。
Slf4j(simple Logging Facade for java)
還是上天提到的ceki大佬(log4j的主要貢獻者),由於某些原因離開了apache,他也覺得jcl問題很多,於是在2005年自己擼了一個新東西,也是一套日志接口,也有稱之為日志門面,slf4j誕生了,並且劍指jcl,並且后來也證明了,slf4j比jcl要更加優秀。
又一次感受到了大佬的能量,一個人單挑一個團隊,還勝的如此漂亮。
但是由於slf4j問世比較晚,而且還只是一套接口,並不是一個可用的日志產品,現有的日志產品雖然不完美但是不用自己去實現,如jul或者log4j,所以對slf4j的推廣造成了很大的阻力,這個時候ceki大佬又出現了,他鍵盤一敲,不就是沒有實現嗎,我來!
大佬一頓操作擼出了slf4j的橋接包,也就是一種適配器模式
在有了橋接包之后,日志框架關系如下圖:
但是由於很多應用依賴了JCL,而沒有它的橋接包,這個時候ceki:我又來啦,jcl的橋接包也來了
那好,那我們如果再考慮一下這種場景呢?假設哈,你的Java
應用使用了Spring
的第三方的框架,但是假設Spring
默認用JCL
,並且最終用的JUL
打印的日志,但是你的系統使用了Slf4j
作為日志接口,日志產品使用了Log4j
,那。。。不出意外的話。。。你將有兩種日志輸出,兩種日志的打印方式不統一,到時候解決bug的時候就很惱火,而且配置日志的配置文件還需要兩份。
這個時候是亂套了,出來處理問題英雄仍然是ceki大佬,沒有什么事是橋接包解決不了的,如果有,那就再來一個
現在日志框架變成了這樣。
基於log4j的確定,大佬追求完美的路又往前邁了一步,logback誕生了。
logback
logback完美實現了slf4j於是日志架構變成了下圖:
現在有了兩個日志接口,三個日志產品。apache可就坐不住了,新的日志產品又誕生了--log4j2.
Log4j2
2012年apache推出了新項目,log4j2,因為log4j2完全不兼容log4j1.x,而且最巧的是log4j2幾乎涵蓋了logback的全部新特性,log4j2也高了分離式設計,分化成log4j-api和log4j-core,這個log4j-api也是日志接口,log4j-core才是日志產品。
現在我們有了三個日志皆苦,4個日志產品,當然apache也很清楚他們的工作,他們推出了log4j2的橋接包,哈哈。
總結到這可以發現:
1.接口給了無限可能,不寫接口沒有任何擴展性可言
2.沒有什么問題是加一層適配器解決不了的,如果有那就再加一層。
連接了日志的整個框架,在使用的時候我們有什么啟發呢
1. 使用日志接口的api而不是日志產品的api,這樣也符合依賴倒置原則
2. 依賴選擇一個即可
3. 把日志產品依賴設置為optional和runtime scope 其中optional是為了依賴不會被傳遞,比如別人引用了這個jar,就會被迫使用不想使用的依賴
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> <optional>true</optional> </dependency>
而scope
設置為runtime
,是可以保證日志的產品的依賴只有在運行時需要,編譯時不需要,這樣,開發人員就不會在編寫代碼的過程中使用到日志產品的API
了
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j.version}</version> <scope>runtime</scope> </dependency>
ok,到這里就結束了,bye~