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

JAVA SpringBoot統一日志處理原理詳解

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

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

slf4j的使用

現在,我們來看看slf4j的使用,引入maven依賴:

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

按照slf4j官方的說法,,日志記錄方法的調用,不應該來直接調用日志的實現類,而是調用日志抽象層里面的實現方法,獲取通過日志工廠創(chuà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日志門面實現的具體日志輸出框架,如果不指定具體的日志輸出實現,將會找不到具體的日志輸出實例,slf4j的日志輸出過程如圖所示:

slf4j日志輸出過程

從圖中可以看到,應用程序調用了slf4j的api接口以后,具體的實現則是由slf4j日志門面找到對應的日志的系統來實現日志輸出

解決多框架日志不統一問題

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

sfl4j適配日志

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

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

SpringBoot如何處理日志關系

在使用SpringBoot的時候,我們會發(fā)現官方默認使用的是spring‐boot‐starter‐logging這個starter來引入日志系統的,我們展開該依賴的依賴圖,如下:

SpringBoot處理日志關系

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

日志兼容包的包名關系

原來這些日志兼容包的包名與原來的日志框架的包名完全一樣,并且完全按照slf4j的方式實現了一套和以前一樣的API,這樣依賴這些日志框架的開源框架在運行的時候查找對應包名下的class也不會報錯,但熟悉java類加載機制的都知道,兩個jar的包名以及使用的class都一樣的話,加載會出現異常,我們進入spring‐boot‐starter‐logging的pom依賴中一探究竟,最后在maven依賴中發(fā)現了端倪,如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成功的完成了一次日志系統統一的偷天換日操作。

slf4j的橋接原理

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

1、將系統中其他日志框架先排除出去;

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

3、我們導入slf4j其他的實現

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

//slf4j日志調用過程相關的代碼
//根據名稱獲取日志實例
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;
      //查找實現類
      performInitialization();
    }
    ...
    return StaticLoggerBinder.getSingleton().getLoggerFactory();
    ...  
 }

可以看到整個過程中是通過StaticLoggerBinder.getSingleton() 來進行初始化日志工廠操作,而StaticLoggerBinder這個類是從哪來的呢?我們發(fā)現StaticLoggerBinder類并不存在于slf4j的jar中,而是通過查找org/slf4j/impl/StaticLoggerBinder.class類的路徑來發(fā)現具體的實現類,代碼如下:

//設置默認的查找日志實例的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文件

根據slf4j橋接原理改造logger

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

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

想要實現這個功能,有以下兩個思路實現:

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

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

總結

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

相關文章

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

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

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

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

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

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

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

    java實現多個文件壓縮成壓縮包

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

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

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

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

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

    關于SpringCloud分布式系統中實現冪等性的幾種方式

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

    java編程實現基于UDP協議傳輸數據的方法

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

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

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

    原來Java接口多實現還可以這樣玩

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

最新評論