国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SLF4J門面日志框架源碼探索

這篇具有很好參考價值的文章主要介紹了SLF4J門面日志框架源碼探索。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1 SLF4J介紹

SLF4J即Simple Logging Facade for Java,它提供了Java中所有日志框架的簡單外觀或抽象。因此,它使用戶能夠使用單個依賴項處理任何日志框架,例如:Log4j,Logback和JUL(java.util.logging)。通過在類路徑中插入適當(dāng)?shù)?jar 文件(綁定),可以在部署時插入所需的日志框架。如果要更換日志框架,僅僅替換依賴的slf4j bindings。比如,從java.util.logging替換為log4j,僅僅需要用slf4j-log4j12-1.7.28.jar替換slf4j-jdk14-1.7.28.jar。

2 SLF4J源碼分析

我們通過代碼入手,層層加碼,直觀感受SLF4J打印日志,并跟蹤代碼追本溯源。主要了解,SLF4J是如何作為門面和其他日志框架進(jìn)行解耦。

2.1 pom只引用依賴slf4j-api,版本是1.7.30

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

2.1.1 執(zhí)行一個Demo

public class HelloSlf4j {

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(HelloSlf4j.class);
        logger.info("Hello World info");
    }
}

2.1.2 日志提示信息

綁定org.slf4j.impl.StaticLoggerBinder失敗。如果在類路徑上沒有找到綁定,那么 SL??F4J 將默認(rèn)為無操作實現(xiàn)

SLF4J門面日志框架源碼探索

2.1.3 跟蹤源碼

點開方法getLogger(),可以直觀看到LoggerFactory使用靜態(tài)工廠創(chuàng)建Logger。通過以下方法,逐步點擊,報錯也很容易找到,可以在bind()方法看到打印的異常日志信息。

org.slf4j.LoggerFactory#getLogger(java.lang.Class<?>)
org.slf4j.LoggerFactory#getLogger(java.lang.String)
org.slf4j.LoggerFactory#getILoggerFactory
org.slf4j.LoggerFactory#performInitialization
org.slf4j.LoggerFactory#bind

private final static void bind() {
        try {
            Set<URL> staticLoggerBinderPathSet = null;
            // skip check under android, see also
            // http://jira.qos.ch/browse/SLF4J-328
            if (!isAndroid()) {
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            // the next line does the binding
            StaticLoggerBinder.getSingleton();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(staticLoggerBinderPathSet);
        } catch (NoClassDefFoundError ncde) {
            String msg = ncde.getMessage();
            if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
                INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
                Util.report("Failed to load class "org.slf4j.impl.StaticLoggerBinder".");
                Util.report("Defaulting to no-operation (NOP) logger implementation");
                Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
            } else {
                failedBinding(ncde);
                throw ncde;
            }
        } catch (java.lang.NoSuchMethodError nsme) {
            String msg = nsme.getMessage();
            if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
                INITIALIZATION_STATE = FAILED_INITIALIZATION;
                Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
                Util.report("Your binding is version 1.5.5 or earlier.");
                Util.report("Upgrade your binding to version 1.6.x.");
            }
            throw nsme;
        } catch (Exception e) {
            failedBinding(e);
            throw new IllegalStateException("Unexpected initialization failure", e);
        } finally {
            postBindCleanUp();
        }
    }

進(jìn)一步分析綁定方法findPossibleStaticLoggerBinderPathSet(),可以發(fā)現(xiàn)在當(dāng)前ClassPath下查詢了所有該路徑的資源“org/slf4j/impl/StaticLoggerBinder.class”,這里可能沒有加載到任何文件,也可能綁定多個,對沒有綁定和綁定多個的場景進(jìn)行了友好提示。這里通過路徑加載資源的目的主要用來對加載的各種異常場景提示。

再往下代碼StaticLoggerBinder.getSingleton()才是實際的綁定,并且獲取StaticLoggerBinder的實例。這里如果反編譯,你會發(fā)現(xiàn)根本沒有這個類StaticLoggerBinder。

如果沒有加載到文件,正如上邊demo執(zhí)行的結(jié)果一樣,命中NoSuchMethodError異常,并打印沒有綁定場景的提示信息。

方法findPossibleStaticLoggerBinderPathSet()的源碼如下,可以發(fā)現(xiàn)類加載器通過路徑獲取URL資源。

            ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
            Enumeration<URL> paths;
            if (loggerFactoryClassLoader == null) {
                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
            } else {
                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
            }

2.2 pom引用依賴logback-classic

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

2.2.1 執(zhí)行demo

可以看到正常的打印日志信息,并且沒有任何異常

SLF4J門面日志框架源碼探索

2.2.2 跟蹤源碼

這個時候如果再點擊進(jìn)入方法StaticLoggerBinder.getSingleton(),發(fā)現(xiàn)類StaticLoggerBinder是由包logback-classic提供的,并且實現(xiàn)了SLF4J中的接口LoggerFactoryBinder。StaticLoggerBinder的創(chuàng)建用到了單例模式,該類主要目的返回一個創(chuàng)建Logger的工廠。這里實際返回了ch.qos.logback.classic.LoggerContext的實例,再由該實例創(chuàng)建ch.qos.logback.classic.Logger。

UML類圖如下:

SLF4J門面日志框架源碼探索

2.3 pom再引入log4j-slf4j-impl

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.9.1</version>
        </dependency>

2.3.1 執(zhí)行demo

打印日志如下,提示綁定了兩個StaticLoggerBinder.class,但最終實際綁定的是ch.qos.logback.classic.util.ContextSelectorStaticBinder。這里邊也驗證了一旦一個類被加載之后,全局限定名相同的類就無法被加載了。這里Jar包被加載的順序直接決定了類加載的順序。

SLF4J: Found binding in [jar:file:/D:/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.9.1/log4j-slf4j-impl-2.9.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
18:19:43.521 [main] INFO com.cj.HelloSlf4j - Hello World info

2.4 log4j-slf4j-impl和logback-classic的引入位置變換

如果Pom文件先引入log4j-slf4j-impl,再引入logback-classic

2.4.1 執(zhí)行demo

根據(jù)日志打印結(jié)果,可以看到實際綁定的是org.apache.logging.slf4j.Log4jLoggerFactory;但是沒有正常打印出日志,需要進(jìn)行l(wèi)og4j2的日志配置。說明實際綁定的是og4j-slf4j-impl包中的org/slf4j/impl/StaticLoggerBinder.class文件;這里也驗證了如果有引入了多個橋接包,實際綁定的是先加載到的文件;

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.9.1/log4j-slf4j-impl-2.9.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console. Set system property 'log4j2.debug' to show Log4j2 internal initialization logging.

2.5 類加載方式的變化

2.5.1 slf4j-api-1.7.30版本的打包技巧

反編譯看slf4j-api-1.7.30-sources.jar,發(fā)現(xiàn)壓根沒有這個類org.slf4j.impl.StaticLoggerBinder,他怎么會編譯成功呢?猜想是不是打包的時候把這個類排除掉了呢?通過git下載源碼發(fā)現(xiàn)slf4j源碼其實是有這個文件的,org/slf4j/impl/StaticLoggerBinder.class;這里使用了一個小技巧,打包的時候把實現(xiàn)類排除掉了,雖然不太優(yōu)雅,但是思路很巧妙。

2.5.2 slf4j-api-2.0.0版本引入SPI(Service Provider Interface)

該版本通過使用SPI方式進(jìn)行實現(xiàn)類的加載,感覺比之前的實現(xiàn)方式優(yōu)雅了很多。橋接包只需要在這個位置:META-INF/services/,定義一個文件org.slf4j.spi.SLF4JServiceProvider(命名為SLFJ4提供的接口名),并且文件中指定實現(xiàn)類。只要引入這個橋接包,就可以適配到對應(yīng)實現(xiàn)的日志框架。

以下是SPI方式加載的源碼

private static List<SLF4JServiceProvider> findServiceProviders() {
        ServiceLoader<SLF4JServiceProvider> serviceLoader = ServiceLoader.load(SLF4JServiceProvider.class);
        List<SLF4JServiceProvider> providerList = new ArrayList();
        Iterator var2 = serviceLoader.iterator();

        while(var2.hasNext()) {
            SLF4JServiceProvider provider = (SLF4JServiceProvider)var2.next();
            providerList.add(provider);
        }

        return providerList;
     }

2.5.3 類加載方式對比

SLF4J門面日志框架源碼探索

2.6 SLF4J官方已經(jīng)實現(xiàn)綁定的日志框架

slf4j已經(jīng)提供了常用日志框架的橋接包,以及詳細(xì)的文檔描述,使用起來非常簡單。
下圖是SLF4J官網(wǎng)中提供的,表示了各種日志實現(xiàn)框架和SLF4J的關(guān)系:

SLF4J門面日志框架源碼探索

2.7 總結(jié)

  • SLF4J API旨在一次綁定一個且僅一個底層日志框架。而且引入SLF4J后,不管是否可以加載到StaticLoggerBinder,或者加載到多個StaticLoggerBinder,都進(jìn)行友好提示,用戶體驗上考慮都很周到。如果類路徑上存在多個綁定,SLF4J 將發(fā)出警告,列出這些綁定的位置。當(dāng)類路徑上有多個綁定可用時,應(yīng)該選擇一個希望使用的綁定,然后刪除其他綁定。
  • 單純看SLF4J源碼,其實整體設(shè)計實現(xiàn)上都很簡單明確,定位非常清楚,就是做好門面。
  • 鑒于 SLF4J 接口及其部署模型的簡單性,新日志框架的開發(fā)人員應(yīng)該會發(fā)現(xiàn)編寫 SLF4J 綁定非常容易。
  • 對于目前比較主流的日志框架都通過實現(xiàn)適配進(jìn)行兼容支持。只要用戶選擇了SLF4J,就可以確保以后變更日志框架的自由。

3 SLF4J設(shè)計模式的使用

在slf4j中用到了一些經(jīng)典的設(shè)計模式,比如門面模式、單例模式、靜態(tài)工廠模式等,我們來分析以下幾種設(shè)計模式。

3.1 門面模式(Facade Pattern)

1)解釋

門面模式,也叫外觀模式,要求一個子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個統(tǒng)一的對象進(jìn)行。門面模式提供一個高層次的接口,使得子系統(tǒng)更易于使用。使用了門面模式,使客戶端調(diào)用變得更加簡單。

Slf4j制定了log日志的使用標(biāo)準(zhǔn),提供了高層次的接口, 我們編碼過程只需要依賴接口Logger和工廠類 LoggerFactory就可以實現(xiàn)日志的打印,完全不用關(guān)心日志內(nèi)部的實現(xiàn)細(xì)節(jié)是logback實現(xiàn)的方式,還是log4j的實現(xiàn)方式。

2)圖解

SLF4J門面日志框架源碼探索

        Logger logger = LoggerFactory.getLogger(HelloSlf4j.class);
        logger.info("Hello World info");

3)優(yōu)點

解耦,減少系統(tǒng)的相互依賴。所有的依賴都是對門面對象的依賴,與子系統(tǒng)無關(guān),業(yè)務(wù)層的開發(fā)不需要關(guān)心底層日志框架的實現(xiàn)及細(xì)節(jié),在編碼的時候也不需要考慮日后更換框架所帶來的成本。
接口和實現(xiàn)分離,屏蔽了底層的實現(xiàn)細(xì)節(jié),面向接口編程。

3.2 單例模式(Singleton Pattern)

1)解釋

單例模式,確保一個類僅有一個實例,并提供一個訪問它的全局訪問點。
在SLF4J的適配包中都需要實現(xiàn)類StaticLoggerBinder,而類StaticLoggerBinder的實現(xiàn)就用了單例模式,而且是最簡單的實現(xiàn)方法,在靜態(tài)初始化器中直接new StaticLoggerBinder(),提供全局訪問方法獲取該實例。

2)UML圖

SLF4J門面日志框架源碼探索

3)優(yōu)點

在單例模式中,活動的單例只有一個實例,對單例類的所有實例化得到的都是相同的一個實例。這樣就防止其它對象對自己的實例化,確保所有的對象都訪問一個實例
單例模式具有一定的伸縮性,類自己來控制實例化進(jìn)程,類就在改變實例化進(jìn)程上有相應(yīng)的伸縮性。

提供了對唯一實例的受控訪問。

在內(nèi)存里只有一個實例,減少了內(nèi)存的開銷,提高系統(tǒng)的性能。

4 啟示

  • 盡管SLF4J整體代碼短小但很精煉,可見門面模式運用好的威力。門面模式也為我們提供了對于多版本的實現(xiàn)如何統(tǒng)一定義接口以及兼容提供了參考。
  • SLF4J定義和實現(xiàn)方案對用戶都很友好,同時又提供了各種橋接包,進(jìn)行完善的文檔指導(dǎo)使用??傊黜椨脩趔w驗都很棒,這也許也是SLF4J目前最受歡迎的原因之一吧。
  • 我們要多思考面向接口編程的思想,降低代碼耦合度,提高代碼擴(kuò)展性。
  • 使用SPI的方式,優(yōu)雅的加載擴(kuò)展實現(xiàn)。
  • 好產(chǎn)品是設(shè)計出來的,更是優(yōu)化迭代出來的。

5 參考資料

  • slf4j官網(wǎng):https://www.slf4j.org/manual.html
    類加載:
  • https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html
  • https://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html
  • https://www.ibm.com/docs/en/sdk-java-technology/7.1?topic=cl-parent-delegation-model-1

作者:京東物流 曹俊

來源:京東云開發(fā)者社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-493301.html

到了這里,關(guān)于SLF4J門面日志框架源碼探索的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【SpringBoot中使用SLE4J日志框架啟動報錯:SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinde】

    【SpringBoot中使用SLE4J日志框架啟動報錯:SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinde】

    1.1 出現(xiàn)的問題 SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”. SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 1.2 原因分析 檢查自己的maven依賴,發(fā)現(xiàn)已經(jīng)引入了slf4j-api了,這是為什么呢?其原因是,SLF4J本身

    2024年02月13日
    瀏覽(21)
  • 如何在 Spring Boot 中集成日志框架 SLF4J、Log4j

    如何在 Spring Boot 中集成日志框架 SLF4J、Log4j

    筆者的操作環(huán)境: Spring Cloud Alibaba:2022.0.0.0-RC2 Spring Cloud:2022.0.0 Spring Boot:3.0.2 Nacos 2.2.3 Maven 3.8.3 JDK 17.0.7 IntelliJ IDEA 2022.3.1 (Ultimate Edition) 因為 Spring Boot 已經(jīng)內(nèi)置了 Logback,所以需要先將 Logback 移除。移除的方法是在 Spring Boot 依賴包中移除 Logback。 比如就像這樣: 【踩坑提

    2024年02月13日
    瀏覽(25)
  • SpringBoot集成slf4j日志系統(tǒng)

    SpringBoot集成slf4j日志系統(tǒng)

    作者平臺: | CSDN:blog.csdn.net/qq_4115394… | 掘金:juejin.cn/user/651387… | 知乎:www.zhihu.com/people/1024… | GitHub:github.com/JiangXia-10… | 微信公眾號:1024筆記 本文大約4777字,預(yù)計閱讀時長11分鐘 日志系統(tǒng)作為一個應(yīng)用系統(tǒng)的重要部分之一,它能夠有助于我們在系統(tǒng)在線上環(huán)境中如果

    2023年04月19日
    瀏覽(18)
  • Spring Boot 日志配置(Slf4j)

    Spring Boot 日志配置(Slf4j)

    SLF4J與Logback簡介 Java日志框架眾多,常用的有java.util.logging, log4j, logback,commons-logging等。 SLF4J (Simple Logging Facade For Java),它是一個針對于各類Java日志框架的統(tǒng)一Facade抽象。SLF4J定義了統(tǒng)一的日志抽象接口,而真正的日志實現(xiàn)則是在運行時決定。 LogBack是由log4j的創(chuàng)始人開發(fā)的新

    2024年02月16日
    瀏覽(26)
  • 日志框架梳理(Log4j,Reload4j,JUL,JCL,SLF4J,Logback,Log4j2)

    文中代碼示例獲?。宏P(guān)注【 Qin的學(xué)習(xí)營地 】,回復(fù)【 日志框架梳理 】 在了解日志框架時總會列出一系列框架:Log4j,Reload4j,JUL,JCL,SLF4J,Logback,Log4j2,這么多框架讓人感到混亂,該怎么選取、該怎么用。接下來,讓我們逐步理清這些框架及之間的關(guān)系。 首先來了解日志

    2024年02月05日
    瀏覽(61)
  • Spring Boot日志:SLF4J和Logback

    Spring Boot日志:SLF4J和Logback

    SpringBoot中的日志庫分為兩種: 實現(xiàn)庫:提供具體的日志實現(xiàn),例如日志級別的控制、打印格式、輸出目標(biāo)等。 外觀庫:自身不提供日志實現(xiàn),而是對其他日志庫進(jìn)行封裝,從而方便使用?;谕庥^模式實現(xiàn)。 關(guān)于外觀庫的出現(xiàn),可設(shè)想一下:現(xiàn)在有多種日志庫,每一種接口

    2024年02月15日
    瀏覽(76)
  • 6.2 SpringBoot日志入門實戰(zhàn) SLF4J + Logback

    6.2 SpringBoot日志入門實戰(zhàn) SLF4J + Logback

    如果你是一位Java開發(fā)者,那么你肯定知道Log日志的重要性,它是我們了解程序內(nèi)部運行真像,分析和定位問題的最直接手段!對于任何企業(yè)級的程序,日志記錄是必須的! 在SpringBoot框架中,集成了常用的日志框架,包括SLF4J、Logback、Log4j2、Java Util Logging等,其中,Logback是

    2024年02月08日
    瀏覽(26)
  • 【JavaEE進(jìn)階】 關(guān)于?志框架(SLF4J)

    【JavaEE進(jìn)階】 關(guān)于?志框架(SLF4J)

    SLF4J不同于其他?志框架,它不是?個真正的?志實現(xiàn),?是?個抽象層,對?志框架制定的?種規(guī)范、標(biāo)準(zhǔn)、接?.所有SLF4J并不能獨?使?,需要和具體的?志框架配合使? SLF4J是??模式的典型應(yīng)?(但不僅僅使?了??模式). ??模式(Facade Pattern)?稱為外觀模式,提供了?個

    2024年01月22日
    瀏覽(48)
  • 學(xué)習(xí)SpringBoot使用slf4j日志并輸出到文件中

    學(xué)習(xí)SpringBoot使用slf4j日志并輸出到文件中

    再使用前,先了解一下介紹,否則你也不會用! 1、日志級別 SLF4J將日志分為trace、debug、info、warn、error五個級別,每個級別對應(yīng)記錄不同的日志,對應(yīng)不同的使用場景。 日志級別從低到高分為 TRACE DEBUG INFO WARN ERROR FATAL 如果設(shè)置為 WARN ,則低于 WARN 的信息都不會輸出 一般設(shè)

    2024年02月06日
    瀏覽(28)
  • SpringBoot集成slf4j日志和logback.xml配置詳解

    SpringBoot集成slf4j日志和logback.xml配置詳解

    slf4j,即(Simple Logging Facade for Java,簡單門面日志)。它是對所有日志框架制定的一種 規(guī)范、標(biāo)準(zhǔn)、接口 ,并不是一個框架的具體的實現(xiàn),它只服務(wù)于各種各樣的日志系統(tǒng)。 slf4j提供了統(tǒng)一的記錄日志的接口,對不同日志系統(tǒng)的具體實現(xiàn)進(jìn)行了抽象化,只要按照其提供的方法記

    2024年02月03日
    瀏覽(42)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包