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

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

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

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

slf4j的使用

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

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

按照slf4j官方的說法,,日志記錄方法的調(diào)用,不應(yīng)該來直接調(diào)用日志的實現(xiàn)類,而是調(diào)用日志抽象層里面的實現(xiàn)方法,獲取通過日志工廠創(chuàng)建的日志實例,即可輸出對應(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日志輸出過程.png-6f5073-1583207284091-0)]
    logger.info("Hello World");
 }
}

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

slf4j日志輸出過程

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

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

現(xiàn)在我們再回到日志統(tǒng)一的問題上,前面已經(jīng)了解了,開發(fā)常用的框架,如Spring、mybatis等使用的框架都是框架開發(fā)者自己選擇的,如果我們每個框架就引入一個日志系統(tǒng),并且最終需要打印日志的時候,會出現(xiàn)使用n種日志系統(tǒng)平臺,并且每一種的日志打印的格式、內(nèi)容和性能都需要手動控制,不僅讓項目變大,而且增大了項目復(fù)雜度,對性能也有很大的影響,那么我們該如何讓所有的開源框架統(tǒng)一使用Slf4j來輸出呢?我們來看下slf4j官方給我們的方案,如圖所示:

sfl4j適配日志

從圖中我們可以看出來,官方的方案是針對不同的日志框架,開發(fā)了一套適配兼容的框架與之對應(yīng),使用這些兼容jar來替代原來的日志框架即可,例如log4j日志框架,與之對應(yīng)的就是log4j-over-slf4j.jar,并且常見的日志框架,slf4j團隊都實現(xiàn)了一套與之對應(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的時候,我們會發(fā)現(xiàn)官方默認使用的是spring‐boot‐starter‐logging這個starter來引入日志系統(tǒng)的,我們展開該依賴的依賴圖,如下:

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

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

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

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

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

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

slf4j的橋接原理

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

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

2、用中間包來替換原有的日志框架;

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

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

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

可以看到整個過程中是通過StaticLoggerBinder.getSingleton() 來進行初始化日志工廠操作,而StaticLoggerBinder這個類是從哪來的呢?我們發(fā)現(xiàn)StaticLoggerBinder類并不存在于slf4j的jar中,而是通過查找org/slf4j/impl/StaticLoggerBinder.class類的路徑來發(fā)現(xiàn)具體的實現(xià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);
  ......
}

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

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

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

3.java -classpath/-Djava.class.path所指的目錄下的類與jar包

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

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

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

7.項目/WEB-INF/classes下的class文件

8.項目/WEB-INF/lib下的jar文件

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

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

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

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

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

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

總結(jié)

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

相關(guān)文章

  • Java隊列篇之實現(xiàn)數(shù)組模擬隊列及可復(fù)用環(huán)形隊列詳解

    Java隊列篇之實現(xiàn)數(shù)組模擬隊列及可復(fù)用環(huán)形隊列詳解

    像棧一樣,隊列(queue)也是一種線性表,它的特性是先進先出,插入在一端,刪除在另一端。就像排隊一樣,剛來的人入隊(push)要排在隊尾(rear),每次出隊(pop)的都是隊首(front)的人
    2021-10-10
  • logback的LevelFilter日志過濾器源碼解讀

    logback的LevelFilter日志過濾器源碼解讀

    這篇文章主要為大家介紹了logback的LevelFilter日志過濾器源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • 一篇文章帶你搞定SpringBoot不重啟項目實現(xiàn)修改靜態(tài)資源

    一篇文章帶你搞定SpringBoot不重啟項目實現(xiàn)修改靜態(tài)資源

    這篇文章主要介紹了一篇文章帶你搞定SpringBoot不重啟項目實現(xiàn)修改靜態(tài)資源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • java實現(xiàn)多個文件壓縮成壓縮包

    java實現(xiàn)多個文件壓縮成壓縮包

    這篇文章主要為大家詳細介紹了java實現(xiàn)多個文件壓縮成壓縮包,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • 在Java中實現(xiàn)讓線程按照自己指定的順序執(zhí)行

    在Java中實現(xiàn)讓線程按照自己指定的順序執(zhí)行

    這篇文章主要介紹了在Java中實現(xiàn)讓線程按照自己指定的順序執(zhí)行,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 一文帶你深入認識JAVA中的異常

    一文帶你深入認識JAVA中的異常

    Java異常處理成為社區(qū)中討論最多的話題之一,下面這篇文章主要給大家介紹了關(guān)于JAVA中異常的相關(guān)資料,文中通過代碼介紹的非常詳細,對大家學習或者使用java具有一定的參考借鑒價值,需要的朋友可以參考下
    2024-06-06
  • 關(guān)于SpringCloud分布式系統(tǒng)中實現(xiàn)冪等性的幾種方式

    關(guān)于SpringCloud分布式系統(tǒng)中實現(xiàn)冪等性的幾種方式

    這篇文章主要介紹了關(guān)于SpringCloud分布式系統(tǒng)中實現(xiàn)冪等性的幾種方式,冪等函數(shù),或冪等方法,是指可以使用相同參數(shù)重復(fù)執(zhí)行,并能獲得相同結(jié)果的函數(shù),這些函數(shù)不會影響系統(tǒng)狀態(tài),也不用擔心重復(fù)執(zhí)行會對系統(tǒng)造成改變,需要的朋友可以參考下
    2023-10-10
  • java編程實現(xiàn)基于UDP協(xié)議傳輸數(shù)據(jù)的方法

    java編程實現(xiàn)基于UDP協(xié)議傳輸數(shù)據(jù)的方法

    這篇文章主要介紹了java編程實現(xiàn)基于UDP協(xié)議傳輸數(shù)據(jù)的方法,較為詳細的分析了UDP協(xié)議的原理及Java編程實現(xiàn)數(shù)據(jù)傳輸客戶端與服務(wù)器端的相關(guān)技巧,需要的朋友可以參考下
    2015-11-11
  • java執(zhí)行shell命令及日志收集避坑指南分享

    java執(zhí)行shell命令及日志收集避坑指南分享

    這篇文章主要介紹了java執(zhí)行shell命令及日志收集避坑指南,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • 原來Java接口多實現(xiàn)還可以這樣玩

    原來Java接口多實現(xiàn)還可以這樣玩

    JAVA中類不直接支持多繼承,因為會出現(xiàn)調(diào)用的不確定性,所以JAVA將多繼承機制進行改良,在JAVA中變成了多實現(xiàn),這篇文章主要給大家介紹了關(guān)于Java接口多實現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2021-09-09

最新評論