摘要:按照官方的說法,是一個用于日志系統的簡單,允許最終用戶在部署其應用時使用其所希望的日志系統。這個方法里就會通過去綁定具體的日志實現。我們直接看一下中的的源碼實現首先通過判斷一個類是否已經被加載過。
SLF4J,即簡單日志門面(Simple Logging Facade for Java),不是具體的日志解決方案,而是通過Facade Pattern提供一些Java logging API,它只服務于各種各樣的日志系統。按照官方的說法,SLF4J是一個用于日志系統的簡單Facade,允許最終用戶在部署其應用時使用其所希望的日志系統。
實際上,SLF4J所提供的核心API是一些接口以及一個LoggerFactory的工廠類。在使用SLF4J的時候,不需要在代碼中或配置文件中指定你打算使用那個具體的日志系統。SLF4J提供了統一的記錄日志的接口,只要按照其提供的方法記錄即可,最終日志的格式、記錄級別、輸出方式等通過具體日志系統的配置來實現,因此可以在應用中靈活切換日志系統。具體的日志系統可以選用log4j,log4j2,logback等。
1.SLF4J 怎么找到具體的實現?
SLF4J的實現是通過org.slf4j.impl.StaticLoggerBinder 來進行加載具體的實現的
org.slf4j.impl.StaticLoggerBinder的代碼實現(log4j2):
public final class StaticLoggerBinder implements LoggerFactoryBinder { /** * Declare the version of the SLF4J API this implementation is compiled * against. The value of this field is usually modified with each release. */ // to avoid constant folding by the compiler, this field must *not* be final public static String REQUESTED_API_VERSION = "1.6"; // !final private static final String LOGGER_FACTORY_CLASS_STR = Log4jLoggerFactory.class.getName(); /** * The unique instance of this class. */ private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); /** * The ILoggerFactory instance returned by the {@link #getLoggerFactory} * method should always be the same object */ private final ILoggerFactory loggerFactory; /** * Private constructor to prevent instantiation */ private StaticLoggerBinder() { loggerFactory = new Log4jLoggerFactory(); } /** * Returns the singleton of this class. * * @return the StaticLoggerBinder singleton */ public static StaticLoggerBinder getSingleton() { return SINGLETON; } /** * Returns the factory. * @return the factor. */ @Override public ILoggerFactory getLoggerFactory() { return loggerFactory; } /** * Returns the class name. * @return the class name; */ @Override public String getLoggerFactoryClassStr() { return LOGGER_FACTORY_CLASS_STR; } }
logback 的實現也是大同小異,都是實現 LoggerFactoryBinder 接口,然后再實現里提供ILoggerFactory的實現類給SLF4J 用來做到日志框架的綁定。
private Logger logger = LoggerFactory.getLogger(DynamicProxy.class);
LoggerFactory.getLogger(DynamicProxy.class) 是靜態方法,SLF4J 在這里進行具體實現的綁定。
在這里有一塊同步代碼,確保ILoggerFactory 只有一個。
這個方法里就會通過 StaticLoggerBinder.getSingleton(); 去綁定具體的日志實現。
2.當項目里同時存在多個日志框架(用來實現SLF4J)的時候,系統會選擇哪一個
這個是通過jvm的類加載機制來控制的,會選擇classpath 路徑里面出現在前面的哪一個日志框架
jvm包括三種類加載器:
第一種:bootstrap classloader:加載java的核心類。
第二種:extension classloader:負責加載jre的擴展目錄中的jar包。
第三種:它負責在JVM被啟動時,加載來自在命令java中的-classpath或者java.class.path系統屬性或者?CLASSPATH操作系統屬性所指定的JAR類包和類路徑。
jvm 加載包名和類名相同的類時,先加載classpath中jar路徑放在前面的,包名類名都相同,那jvm沒法區分了,如果使用ide一般情況下是會提示發生沖突而報錯,若不報錯,只有第一個包被引入(在classpath路徑下排在前面的包),第二個包會在classloader加載類時判斷重復而忽略。
類加載器
虛擬機設計團隊把加載動作放到JVM外部實現,以便讓應用程序決定如何獲取所需的類,JVM提供了3種類加載器:
· 啟動類加載器(Bootstrap ClassLoader):負責加載 JAVA_HOMElib 目錄中的,或通過-Xbootclasspath參數指定路徑中的,且被虛擬機認可(按文件名識別,如rt.jar)的類。
· 擴展類加載器(Extension ClassLoader):負責加載 JAVA_HOMElibext 目錄中的,或通過java.ext.dirs系統變量指定路徑中的類庫。
· 應用程序類加載器(Application ClassLoader):負責加載用戶路徑(classpath)上的類庫。
JVM通過雙親委派模型進行類的加載,當然我們也可以通過繼承java.lang.ClassLoader實現自定義的類加載器。
當一個類加載器收到類加載任務,會先交給其父類加載器去完成,因此最終加載任務都會傳遞到頂層的啟動類加載器,只有當父類加載器無法完成加載任務時,才會嘗試執行加載任務。
采用雙親委派的一個好處是比如加載位于rt.jar包中的類java.lang.Object,不管是哪個加載器加載這個類,最終都是委托給頂層的啟動類加載器進行加載,這樣就保證了使用不同的類加載器最終得到的都是同樣一個Object對象。
在有些情境中可能會出現要我們自己來實現一個類加載器的需求,由于這里涉及的內容比較廣泛,我想以后多帶帶寫一篇文章來講述,不過這里我們還是稍微來看一下。我們直接看一下jdk中的ClassLoader的源碼實現:
protected synchronized Class> loadClass(String name, boolean resolve) ????????throws ClassNotFoundException { ????// First, check if the class has already been loaded ????Class c = findLoadedClass(name); ????if (c == null) { ????????try { ????????????if (parent != null) { ????????????????c = parent.loadClass(name, false); ????????????} else { ????????????????c = findBootstrapClass0(name); ????????????} ????????} catch (ClassNotFoundException e) { ????????????// If still not found, then invoke findClass in order ????????????// to find the class. ????????????c = findClass(name); ????????} ????} ????if (resolve) { ????????resolveClass(c); ????} ????return c; }
· 首先通過Class c = findLoadedClass(name);判斷一個類是否已經被加載過。
· 如果沒有被加載過執行if (c == null)中的程序,遵循雙親委派的模型,首先會通過遞歸從父加載器開始找,直到父類加載器是Bootstrap ClassLoader為止。
· 最后根據resolve的值,判斷這個class是否需要解析。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76961.html
摘要:我開發了一個應用,部署到云環境上之后,用測試發現不能按照我期望的工作,但是返回的消息對我沒有任何幫助。的使用非常簡單,在您的應用代碼里將的和導入然后在引用代碼里用獲得實例然后用進行日志記錄。 我開發了一個Java應用,部署到云環境上之后,用postman測試發現不能按照我期望的工作,但是返回的消息對我沒有任何幫助。 showImg(https://segmentfault.com/im...
摘要:一引言程序員都知道,日志對于一個應用系統來說至關重要,現在應該也沒有無日志的系統了吧。具體的日志實現還是需要使用不同的日志框架來完成。然后如下使用測試測試測試測試運行結果發現并沒有打印出日志,這是因為缺少了配置文件。 一、引言 程序員都知道,日志對于一個應用系統來說至關重要,現在應該也沒有無日志的系統了吧。很多程序員都知道 Log4j,Logback,java.util.loggi...
摘要:所有示例代碼請見下載于基本概念并發同時擁有兩個或者多個線程,如果程序在單核處理器上運行多個線程將交替地換入或者換出內存這些線程是同時存在的,每個線程都處于執行過程中的某個狀態,如果運行在多核處理器上此時,程序中的每個線程都 所有示例代碼,請見/下載于 https://github.com/Wasabi1234... showImg(https://upload-images.jians...
摘要:概述應用中,日志一般分為以下個級別錯誤信息警告信息一般信息調試信息跟蹤信息使用的作為內部的日志框架,其僅僅是一個日志接口,在實際應用中需要為該接口來指定相應的日志實現。默認的日志實現是,是自帶的日志包,此外當然也支持這類很流行的日志實現。 showImg(https://segmentfault.com/img/remote/1460000014055501); 概述 Java應用中...
摘要:想要看級別的信息,你需要在啟動時傳入這個系統屬性使用與日志現在我們可以試驗并更換不同的日志實現,但你的程序代碼可以保持不變。我們要做的是用另一個流行的日志實現來替換掉,比如。又一次,我們必須對我們選的每一個日志實現做配置。 使用slf4j庫作為你的Java應用日志API層有很多好處,這里我會展示一小部分關于如何使用和配置它的例子。 你可以把slf4j想成一個Java的接口,然后你需要實...
閱讀 662·2021-11-24 09:39
閱讀 2315·2021-11-22 13:54
閱讀 2197·2021-09-23 11:46
閱讀 3246·2019-08-30 15:55
閱讀 2679·2019-08-30 15:54
閱讀 2403·2019-08-30 14:18
閱讀 1546·2019-08-29 14:15
閱讀 2732·2019-08-29 13:49