欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA SpringBoot統(tǒng)一日志處理原理詳解

 更新時(shí)間:2021年09月02日 10:39:16   作者:面試秘籍Java  
這篇文章主要介紹了SpringBoot的統(tǒng)一日志處理原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
框架 日志
Spring JCL
SpringBoot Sfl4j–>logback
Hibernate3 Slf4j
Struts2 LoggerFactory(com.opensymphony.xwork2.util.logging.LoggerFactory)

由于歷史迭代原因,JCLjboss-logging日志框架,基本已經(jīng)很久沒(méi)有更新了,不太適合作為現(xiàn)在框架的主流選擇,那么剩下的選擇中log4j、slf4j是使用最多的,然而由于log4j的輸出性能問(wèn)題,log4j的作者選擇重新編寫(xiě)了一個(gè)日志門(mén)面–Slf4j,并且編寫(xiě)了基于Slf4j的日志實(shí)現(xiàn)–logback,其輸出信息的效率遠(yuǎn)超log4j,解決了log4j遺留下的性能問(wèn)題,所以在SpringBoot框架中,默認(rèn)也選擇了Slf4j來(lái)作為默認(rèn)日志框架

slf4j的使用

現(xiàn)在,我們來(lái)看看slf4j的使用,引入maven依賴(lài):

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.28</version>
</dependency>

按照slf4j官方的說(shuō)法,,日志記錄方法的調(diào)用,不應(yīng)該來(lái)直接調(diào)用日志的實(shí)現(xiàn)類(lèi),而是調(diào)用日志抽象層里面的實(shí)現(xiàn)方法,獲取通過(guò)日志工廠(chǎng)創(chuàng)建的日志實(shí)例,即可輸出對(duì)應(yīng)的日志:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HelloWorld { public static void main(String[] args) { 
 Logger logger =
    LoggerFactory.getLogger(HelloWorld.class);
[圖片上傳中...(slf4j日志輸出過(guò)程.png-6f5073-1583207284091-0)]
    logger.info("Hello World");
 }
}

這里我們注意到了一點(diǎn),使用slf4j的輸出日志的時(shí)候,我們也引入了logback這個(gè)基于slf4j日志門(mén)面實(shí)現(xiàn)的具體日志輸出框架,如果不指定具體的日志輸出實(shí)現(xiàn),將會(huì)找不到具體的日志輸出實(shí)例,slf4j的日志輸出過(guò)程如圖所示:

slf4j日志輸出過(guò)程

從圖中可以看到,應(yīng)用程序調(diào)用了slf4j的api接口以后,具體的實(shí)現(xiàn)則是由slf4j日志門(mén)面找到對(duì)應(yīng)的日志的系統(tǒng)來(lái)實(shí)現(xiàn)日志輸出

解決多框架日志不統(tǒng)一問(wèn)題

現(xiàn)在我們?cè)倩氐饺罩窘y(tǒng)一的問(wèn)題上,前面已經(jīng)了解了,開(kāi)發(fā)常用的框架,如Spring、mybatis等使用的框架都是框架開(kāi)發(fā)者自己選擇的,如果我們每個(gè)框架就引入一個(gè)日志系統(tǒng),并且最終需要打印日志的時(shí)候,會(huì)出現(xiàn)使用n種日志系統(tǒng)平臺(tái),并且每一種的日志打印的格式、內(nèi)容和性能都需要手動(dòng)控制,不僅讓項(xiàng)目變大,而且增大了項(xiàng)目復(fù)雜度,對(duì)性能也有很大的影響,那么我們?cè)撊绾巫屗械拈_(kāi)源框架統(tǒng)一使用Slf4j來(lái)輸出呢?我們來(lái)看下slf4j官方給我們的方案,如圖所示:

sfl4j適配日志

從圖中我們可以看出來(lái),官方的方案是針對(duì)不同的日志框架,開(kāi)發(fā)了一套適配兼容的框架與之對(duì)應(yīng),使用這些兼容jar來(lái)替代原來(lái)的日志框架即可,例如log4j日志框架,與之對(duì)應(yīng)的就是log4j-over-slf4j.jar,并且常見(jiàn)的日志框架,slf4j團(tuán)隊(duì)都實(shí)現(xiàn)了一套與之對(duì)應(yīng)的基于slf4j的兼容框架,關(guān)系如下:

日志框架 slf4j兼容框架
log4j log4j-over-slf4j
commons logging jcl-over-slf4j
java.util.logging jui-to-slf4j

SpringBoot如何處理日志關(guān)系

在使用SpringBoot的時(shí)候,我們會(huì)發(fā)現(xiàn)官方默認(rèn)使用的是spring‐boot‐starter‐logging這個(gè)starter來(lái)引入日志系統(tǒng)的,我們展開(kāi)該依賴(lài)的依賴(lài)圖,如下:

SpringBoot處理日志關(guān)系

可以看到spring‐boot‐starter‐logging這個(gè)starter中,引入了四個(gè)日志實(shí)例的依賴(lài),分別是logback和我們前面提到的日志兼容jar的依賴(lài),并且最終引入了slf4j的日志門(mén)面的依賴(lài),實(shí)現(xiàn)了統(tǒng)一日志處理。但是為什么兼容jar引入后就能解決日志輸出的問(wèn)題呢?難道兼容包有什么神奇的黑科技嗎?其實(shí)不然,我們隨便展開(kāi)其中的幾個(gè)兼容日志jar的包名,如圖:

日志兼容包的包名關(guān)系

原來(lái)這些日志兼容包的包名與原來(lái)的日志框架的包名完全一樣,并且完全按照slf4j的方式實(shí)現(xiàn)了一套和以前一樣的API,這樣依賴(lài)這些日志框架的開(kāi)源框架在運(yùn)行的時(shí)候查找對(duì)應(yīng)包名下的class也不會(huì)報(bào)錯(cuò),但熟悉java類(lèi)加載機(jī)制的都知道,兩個(gè)jar的包名以及使用的class都一樣的話(huà),加載會(huì)出現(xiàn)異常,我們進(jìn)入spring‐boot‐starter‐logging的pom依賴(lài)中一探究竟,最后在maven依賴(lài)中發(fā)現(xiàn)了端倪,如Spring框架使用的是commons-logging,而在spring-boot-starter-logging中,將spring的日志依賴(lài)排除,如下:

<dependency>        
    <groupId>org.springframework</groupId>            
    <artifactId>spring‐core</artifactId>            
    <exclusions>            
        <exclusion>                
        <groupId>commons‐logging</groupId>            
        <artifactId>commons‐logging</artifactId>     
        </exclusion>                
    </exclusions>            
</dependency> 

這樣spring框架在運(yùn)行時(shí)使用的時(shí)候,使用的就是兼容jar中的日志實(shí)例了,SpringBoot成功的完成了一次日志系統(tǒng)統(tǒng)一的偷天換日操作。

slf4j的橋接原理

通過(guò)查看SpringBoot的日志處理,我們可以大致總結(jié)如下幾步操作:

1、將系統(tǒng)中其他日志框架先排除出去;

2、用中間包來(lái)替換原有的日志框架;

3、我們導(dǎo)入slf4j其他的實(shí)現(xiàn)

通過(guò)以上的操作,即可完成日志系統(tǒng)的統(tǒng)一,但是我們開(kāi)始有了新的疑惑,slf4j是怎么做到的自動(dòng)查找對(duì)應(yīng)的實(shí)現(xiàn)日志,并且完成了日志的正常打印操作的呢?這個(gè)就要涉及到slf4j的橋接原理,我們先來(lái)看看slf4j源碼中關(guān)于日志調(diào)用相關(guān)的代碼:

//slf4j日志調(diào)用過(guò)程相關(guān)的代碼
//根據(jù)名稱(chēng)獲取日志實(shí)例
public static Logger getLogger(String name) {
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
}
//獲取日志實(shí)例工廠(chǎng)并且完成日志實(shí)例的查找與初始化操作
 public static ILoggerFactory getILoggerFactory() {
    if (INITIALIZATION_STATE == UNINITIALIZED) {
      INITIALIZATION_STATE = ONGOING_INITIALIZATION;
      //查找實(shí)現(xiàn)類(lèi)
      performInitialization();
    }
    ...
    return StaticLoggerBinder.getSingleton().getLoggerFactory();
    ...  
 }

可以看到整個(gè)過(guò)程中是通過(guò)StaticLoggerBinder.getSingleton() 來(lái)進(jìn)行初始化日志工廠(chǎng)操作,而StaticLoggerBinder這個(gè)類(lèi)是從哪來(lái)的呢?我們發(fā)現(xiàn)StaticLoggerBinder類(lèi)并不存在于slf4j的jar中,而是通過(guò)查找org/slf4j/impl/StaticLoggerBinder.class類(lèi)的路徑來(lái)發(fā)現(xiàn)具體的實(shí)現(xiàn)類(lèi),代碼如下:

//設(shè)置默認(rèn)的查找日志實(shí)例的StaticLoggerBinder路徑
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
private static Set findPossibleStaticLoggerBinderPathSet() {
  .......
  paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
  ......
}

這個(gè)時(shí)候我們就該思考一個(gè)問(wèn)題,如果我們同時(shí)存在了多個(gè)StaticLoggerBinder 時(shí)會(huì)加載哪一個(gè)呢?熟悉java類(lèi)加載機(jī)制可知,類(lèi)加載器會(huì)按照一定的順序逐個(gè)掃描jar包目錄并且加載出來(lái),所以先被類(lèi)加載器掃描的StaticLoggerBinder會(huì)優(yōu)先被加載,具體的加載順序如下:

1.$java_home/lib 目錄下的java核心api

2.$java_home/lib/ext 目錄下的java擴(kuò)展jar包

3.java -classpath/-Djava.class.path所指的目錄下的類(lèi)與jar包

4.$CATALINA_HOME/common目錄下按照文件夾的順序從上往下依次加載

5.$CATALINA_HOME/server目錄下按照文件夾的順序從上往下依次加載

6.$CATALINA_BASE/shared目錄下按照文件夾的順序從上往下依次加載

7.項(xiàng)目/WEB-INF/classes下的class文件

8.項(xiàng)目/WEB-INF/lib下的jar文件

根據(jù)slf4j橋接原理改造logger

我們都知道平時(shí)使用slf4j輸出日志的時(shí)候往往獲取Logger實(shí)例來(lái)進(jìn)行日志打印,但是Logger僅僅支持本地日志,不支持分布式環(huán)境的日志,而在slfj中有LogBean實(shí)例,可以支持分布式日志,包含了鏈路相關(guān)信息,那么我們是否可以改造slf4j的橋接過(guò)程,使得我們可以靈活的使用本地日志或者分布式日志呢?首先我們先看看我們需要實(shí)現(xiàn)的需求:

  • logger和logbean結(jié)合,統(tǒng)一日志入口
  • logbean降低代碼侵入性
  • 無(wú)縫替換第三方框架中的日志,根據(jù)需求加入到分布式日志中

想要實(shí)現(xiàn)這個(gè)功能,有以下兩個(gè)思路實(shí)現(xiàn):

1.我們通過(guò)自定義appender,基于logback的appender進(jìn)行擴(kuò)展,可以實(shí)現(xiàn)分別輸出本地日志以及分布式日志,但是缺陷在于appender擴(kuò)展性不高,很多參數(shù)信息獲取不到,例如上下文信息等

2.我們通過(guò)實(shí)現(xiàn)Logger接口,用來(lái)將Logger和LogBean聚合在一起,從而實(shí)現(xiàn)LogBean集成到Logger中,同樣此種方式的缺陷在于對(duì)于第三方框架日志,我們無(wú)能為力,無(wú)法直接替換使用,并且在使用的時(shí)候需要使用自定義的LogFactory

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

最新評(píng)論