java日志發展史 log4j slf4j log4j2 jul jcl 日志和各種橋接包的關系


一切事情的發展都是有緣由的,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~ 

 

  


免責聲明!

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



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