一文讲尽门面日志slf4j和log4j、log4j2、logback依赖jar引用关系
前言
之前都是使用SparkStreaming開(kāi)發(fā),最近打算學(xué)習(xí)一下Flink,就從官網(wǎng)下載了Flink 1.11,打算搞一個(gè)客戶(hù)端,將程序提交在yarn上。因?yàn)镕link從1.7之后就不再提供Hadoop的依賴(lài),所以很多依賴(lài)就要自己下載,于是各種ClassNotFoundException,其中以log*.class為首的格外猖狂,可能是因?yàn)閒link和Hadoop的日志實(shí)現(xiàn)有點(diǎn)區(qū)別,就一直哐哐哐報(bào)錯(cuò),slf4j、log4j、logback各種jar包十幾個(gè),百度好久也沒(méi)搞清各個(gè)jar有什么區(qū)別,用在何處,就打算自己總結(jié)一下。
?
log發(fā)展歷史
Long long Ago,和剛學(xué)Java的時(shí)候一樣,都是用System.out.println控制臺(tái)打印來(lái)檢查程序輸出是否符合自己的預(yù)期,這是一種比較原始的方法,無(wú)法自動(dòng)區(qū)分日志的類(lèi)型,幾乎無(wú)法用于生產(chǎn)系統(tǒng)中。
從JDK1.4開(kāi)始提供java.until.logging日志框架來(lái)打印日志,但是大佬覺(jué)得JUL太難用了,就自己手?jǐn)]了個(gè)log4j,后來(lái)log4j發(fā)現(xiàn)安全漏洞,加上代碼結(jié)構(gòu)問(wèn)題難以維護(hù),于是從1.2就停止更新log4j,并又重新手?jǐn)]了個(gè)log4j2,再后來(lái),這個(gè)大佬又又又?jǐn)]了一個(gè)性能更高、功能更全的logback。
從此,這個(gè)大佬構(gòu)建了log的世界,也創(chuàng)造了最常見(jiàn)的日志框架:log4j、log4j2、logback。
?
SLF4J( Simple Logging Facade for Java )
目前已經(jīng)提及了四個(gè)日志框架,如果我們想用來(lái)記錄日志,除了必要的配置文件,還需要在代碼中獲取Logger,打印日志。
代碼如下:
//?使用log4j,需要log4j.jar import?org.apache.log4j.Logger; Logger?logger_log4j?=?Logger.getLogger(Test.class); logger_log4j.info("Hello?World!");//?使用log4j2,需要log4j-api.jar、log4j-core.jar import?org.apache.logging.log4j.LogManager; import?org.apache.logging.log4j.Logger; Logger?logger_log4j2?=?LogManager.getLogger(Test.class); logger_log4j2.info("Hello?World!");//?logback,需要logback-classic.jar、logback-core.jar import?ch.qos.logback.classic.Logger; import?ch.qos.logback.classic.LoggerContext; Logger?logger_logback?=?new?LoggerContext().getLogger(Test.class); logger_logback.info("Hello?World!");//?java.until.logging,簡(jiǎn)稱(chēng)jul import?java.util.logging.Logger; Logger?logger_jul?=?Logger.getLogger("java.Test");為什么要使用門(mén)面系統(tǒng)
從上面不難看出,使用不同的日志框架,就要引入不同的jar包,使用不同的代碼獲取Logger。
假設(shè)一個(gè)項(xiàng)目在漫長(zhǎng)的升級(jí)過(guò)程中,想從jul升級(jí)到logback,那么就需要修改代碼來(lái)獲取新的Logger。如果100個(gè)class中使用了jul,就得修改100個(gè)地方,這是多么一個(gè)繁瑣的工作!!
門(mén)面系統(tǒng)的作用
于是Apache Commons Logging出現(xiàn)了。
Common-logging提供了一個(gè)日志入口,稱(chēng)作"門(mén)面日志",即它不負(fù)責(zé)寫(xiě)日志,而是「提供用一個(gè)統(tǒng)一的接口,通過(guò)jar來(lái)決定使用的日志框架」,這樣就不要再更換框架的時(shí)候再修改代碼了。后來(lái)開(kāi)發(fā)了log4j的大佬又因?yàn)橄訔塁ommon-logging難用,開(kāi)發(fā)了門(mén)面日志框架「slf4j」,今天就拿slf4j講述門(mén)面日志。
門(mén)面日志和設(shè)計(jì)模式中的外觀模式如出一轍,本身不提供服務(wù),為子系統(tǒng)提供統(tǒng)一的入口,封裝子系統(tǒng)的復(fù)雜性,便于客戶(hù)端調(diào)用。slf4j就像是菜鳥(niǎo)驛站,本身沒(méi)有快遞服務(wù),但是提供順豐、中通等快遞服務(wù),至于你想用順豐還是用中通,完全取決于你的想法。
使用slf4j的代碼如下:
import?org.slf4j.Logger; import?org.slf4j.LoggerFactory; Logger?logger?=?LoggerFactory.getLogger(Test.class); logger.info("Hello?World!")這行代碼就像是你在菜鳥(niǎo)驛站里要寄東西(logger),思考到底用哪家快遞?A minute later... ?決定用順豐(logback),就填了順豐的快遞單(放入logback.jar),但是你看微信余額還有10塊,錢(qián)不夠,只能用中通(log4j),于是你就退了順豐的單子(移除logback.jar),填了中通的快遞單(放入log4j.jar),然后發(fā)出快遞(打印日志)。
那么slf4j如何決定使用哪個(gè)框架日志呢,并且引入哪些jar包呢?
如slf4j官方圖所示:
依賴(lài)關(guān)系圖如圖就是slf4j和日志框架的組合依賴(lài)結(jié)構(gòu)圖,使用slf4j需要首先導(dǎo)入「slf4j-api.jar」,
和log4j配合,需要導(dǎo)入「log4j.jar」,以及橋接包「slf4j-log412.jar」。
官方圖美中不足的是沒(méi)有l(wèi)og4j2依賴(lài)jar的關(guān)系,和log4j2配合需要導(dǎo)入log4j2的「log4j-api.jar」、「log4j-core.jar」和橋接包「log4j-slf4j-impl.jar」。
logback只需要導(dǎo)入「logback-classic.jar」和「logback-core.jar」即可,不需要橋接包。
?
什么是橋接包,為什么logback沒(méi)有
先讓來(lái)讓我們看看slf4j從LoggerFactory.getLogger()開(kāi)始,到底干了什么。
流程圖如下:
slf4j工作流程圖原理就是就是讓ClassLoader從classpath(依賴(lài)的jar)中找到「StaticLoggerBinder」這個(gè)類(lèi),然后利用他來(lái)返回log4j、logback中的Logger,然后打印日志。
所謂的橋接包,就是實(shí)現(xiàn)StaticLoggerBinder類(lèi),用來(lái)連接slf4j和日志框架。因?yàn)閘og4j和log4j2剛開(kāi)始沒(méi)有StaticLoggerBinder這個(gè)類(lèi),為了不改變程序結(jié)構(gòu),只能重新寫(xiě)一個(gè)新的jar來(lái)實(shí)現(xiàn)StaticLoggerBinder。而logback出現(xiàn)slf4j之后,于是在logback本身的jar中實(shí)現(xiàn)了StaticLoggerBinder,所以就不需要橋接包。
StaticLoggerBinder實(shí)現(xiàn)了使用底層日志框架創(chuàng)建Logger的功能,各自的StaticLoggerBinder為slf4j提供的Logger,再提供給用戶(hù)打印日志。
log4j和log4j2橋接包及l(fā)ogback依賴(lài)?yán)?#xff0c;都有StaticLoggerBinder類(lèi)。
logback的StaticLoggerBinderlog4j的StaticLoggerBinderlog4j2的StaticLoggerBinder
使用總結(jié)
"Class path contains multiple SLF4J bindings."
在使用slf4j的時(shí)候會(huì)遇到以上的報(bào)告信息。我也曾遇到過(guò)web服務(wù)因?yàn)閟lf4j問(wèn)題啟動(dòng)失敗。究其根本是因?yàn)閘ogback-classic、log4j-slf4j-impl、slf4j-log412、slf4j-jdk這些jar不能同時(shí)存在。他們都實(shí)現(xiàn)了StaticLoggerBinder類(lèi)而導(dǎo)致沖突,slf4j無(wú)法確定到底用哪個(gè)日志框架。
?
結(jié)語(yǔ)
以上是結(jié)合官網(wǎng)以及自己調(diào)試代碼的一些總結(jié),希望對(duì)大家了解slf4j及其應(yīng)用有幫助,其中不足的地方還望指出,共同進(jìn)步,共勉!!!
有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的一文讲尽门面日志slf4j和log4j、log4j2、logback依赖jar引用关系的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Visual C# 2010从入门到精通
- 下一篇: 策略模式和自定义排序规则