1. 程式人生 > 其它 >java日誌發展史 log4j slf4j log4j2 jul jcl 日誌和各種橋接包的關係

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~