摘要:按照官方的說法,是一個(gè)用于日志系統(tǒng)的簡單,允許最終用戶在部署其應(yīng)用時(shí)使用其所希望的日志系統(tǒng)。這個(gè)方法里就會通過去綁定具體的日志實(shí)現(xiàn)。我們直接看一下中的的源碼實(shí)現(xiàn)首先通過判斷一個(gè)類是否已經(jīng)被加載過。
SLF4J,即簡單日志門面(Simple Logging Facade for Java),不是具體的日志解決方案,而是通過Facade Pattern提供一些Java logging API,它只服務(wù)于各種各樣的日志系統(tǒng)。按照官方的說法,SLF4J是一個(gè)用于日志系統(tǒng)的簡單Facade,允許最終用戶在部署其應(yīng)用時(shí)使用其所希望的日志系統(tǒng)。
實(shí)際上,SLF4J所提供的核心API是一些接口以及一個(gè)LoggerFactory的工廠類。在使用SLF4J的時(shí)候,不需要在代碼中或配置文件中指定你打算使用那個(gè)具體的日志系統(tǒng)。SLF4J提供了統(tǒng)一的記錄日志的接口,只要按照其提供的方法記錄即可,最終日志的格式、記錄級別、輸出方式等通過具體日志系統(tǒng)的配置來實(shí)現(xiàn),因此可以在應(yīng)用中靈活切換日志系統(tǒng)。具體的日志系統(tǒng)可以選用log4j,log4j2,logback等。
1.SLF4J 怎么找到具體的實(shí)現(xiàn)?
SLF4J的實(shí)現(xiàn)是通過org.slf4j.impl.StaticLoggerBinder 來進(jìn)行加載具體的實(shí)現(xiàn)的
org.slf4j.impl.StaticLoggerBinder的代碼實(shí)現(xiàn)(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 的實(shí)現(xiàn)也是大同小異,都是實(shí)現(xiàn) LoggerFactoryBinder 接口,然后再實(shí)現(xiàn)里提供ILoggerFactory的實(shí)現(xiàn)類給SLF4J 用來做到日志框架的綁定。
private Logger logger = LoggerFactory.getLogger(DynamicProxy.class);
LoggerFactory.getLogger(DynamicProxy.class) 是靜態(tài)方法,SLF4J 在這里進(jìn)行具體實(shí)現(xiàn)的綁定。
在這里有一塊同步代碼,確保ILoggerFactory 只有一個(gè)。
這個(gè)方法里就會通過 StaticLoggerBinder.getSingleton(); 去綁定具體的日志實(shí)現(xiàn)。
2.當(dāng)項(xiàng)目里同時(shí)存在多個(gè)日志框架(用來實(shí)現(xiàn)SLF4J)的時(shí)候,系統(tǒng)會選擇哪一個(gè)
這個(gè)是通過jvm的類加載機(jī)制來控制的,會選擇classpath 路徑里面出現(xiàn)在前面的哪一個(gè)日志框架
jvm包括三種類加載器:
第一種:bootstrap classloader:加載java的核心類。
第二種:extension classloader:負(fù)責(zé)加載jre的擴(kuò)展目錄中的jar包。
第三種:它負(fù)責(zé)在JVM被啟動時(shí),加載來自在命令java中的-classpath或者java.class.path系統(tǒng)屬性或者?CLASSPATH操作系統(tǒng)屬性所指定的JAR類包和類路徑。
jvm 加載包名和類名相同的類時(shí),先加載classpath中jar路徑放在前面的,包名類名都相同,那jvm沒法區(qū)分了,如果使用ide一般情況下是會提示發(fā)生沖突而報(bào)錯(cuò),若不報(bào)錯(cuò),只有第一個(gè)包被引入(在classpath路徑下排在前面的包),第二個(gè)包會在classloader加載類時(shí)判斷重復(fù)而忽略。
類加載器
虛擬機(jī)設(shè)計(jì)團(tuán)隊(duì)把加載動作放到JVM外部實(shí)現(xiàn),以便讓應(yīng)用程序決定如何獲取所需的類,JVM提供了3種類加載器:
· 啟動類加載器(Bootstrap ClassLoader):負(fù)責(zé)加載 JAVA_HOMElib 目錄中的,或通過-Xbootclasspath參數(shù)指定路徑中的,且被虛擬機(jī)認(rèn)可(按文件名識別,如rt.jar)的類。
· 擴(kuò)展類加載器(Extension ClassLoader):負(fù)責(zé)加載 JAVA_HOMElibext 目錄中的,或通過java.ext.dirs系統(tǒng)變量指定路徑中的類庫。
· 應(yīng)用程序類加載器(Application ClassLoader):負(fù)責(zé)加載用戶路徑(classpath)上的類庫。
JVM通過雙親委派模型進(jìn)行類的加載,當(dāng)然我們也可以通過繼承java.lang.ClassLoader實(shí)現(xiàn)自定義的類加載器。
當(dāng)一個(gè)類加載器收到類加載任務(wù),會先交給其父類加載器去完成,因此最終加載任務(wù)都會傳遞到頂層的啟動類加載器,只有當(dāng)父類加載器無法完成加載任務(wù)時(shí),才會嘗試執(zhí)行加載任務(wù)。
采用雙親委派的一個(gè)好處是比如加載位于rt.jar包中的類java.lang.Object,不管是哪個(gè)加載器加載這個(gè)類,最終都是委托給頂層的啟動類加載器進(jìn)行加載,這樣就保證了使用不同的類加載器最終得到的都是同樣一個(gè)Object對象。
在有些情境中可能會出現(xiàn)要我們自己來實(shí)現(xiàn)一個(gè)類加載器的需求,由于這里涉及的內(nèi)容比較廣泛,我想以后多帶帶寫一篇文章來講述,不過這里我們還是稍微來看一下。我們直接看一下jdk中的ClassLoader的源碼實(shí)現(xiàn):
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);判斷一個(gè)類是否已經(jīng)被加載過。
· 如果沒有被加載過執(zhí)行if (c == null)中的程序,遵循雙親委派的模型,首先會通過遞歸從父加載器開始找,直到父類加載器是Bootstrap ClassLoader為止。
· 最后根據(jù)resolve的值,判斷這個(gè)class是否需要解析。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76961.html
摘要:我開發(fā)了一個(gè)應(yīng)用,部署到云環(huán)境上之后,用測試發(fā)現(xiàn)不能按照我期望的工作,但是返回的消息對我沒有任何幫助。的使用非常簡單,在您的應(yīng)用代碼里將的和導(dǎo)入然后在引用代碼里用獲得實(shí)例然后用進(jìn)行日志記錄。 我開發(fā)了一個(gè)Java應(yīng)用,部署到云環(huán)境上之后,用postman測試發(fā)現(xiàn)不能按照我期望的工作,但是返回的消息對我沒有任何幫助。 showImg(https://segmentfault.com/im...
摘要:一引言程序員都知道,日志對于一個(gè)應(yīng)用系統(tǒng)來說至關(guān)重要,現(xiàn)在應(yīng)該也沒有無日志的系統(tǒng)了吧。具體的日志實(shí)現(xiàn)還是需要使用不同的日志框架來完成。然后如下使用測試測試測試測試運(yùn)行結(jié)果發(fā)現(xiàn)并沒有打印出日志,這是因?yàn)槿鄙倭伺渲梦募? 一、引言 程序員都知道,日志對于一個(gè)應(yīng)用系統(tǒng)來說至關(guān)重要,現(xiàn)在應(yīng)該也沒有無日志的系統(tǒng)了吧。很多程序員都知道 Log4j,Logback,java.util.loggi...
摘要:所有示例代碼請見下載于基本概念并發(fā)同時(shí)擁有兩個(gè)或者多個(gè)線程,如果程序在單核處理器上運(yùn)行多個(gè)線程將交替地?fù)Q入或者換出內(nèi)存這些線程是同時(shí)存在的,每個(gè)線程都處于執(zhí)行過程中的某個(gè)狀態(tài),如果運(yùn)行在多核處理器上此時(shí),程序中的每個(gè)線程都 所有示例代碼,請見/下載于 https://github.com/Wasabi1234... showImg(https://upload-images.jians...
摘要:概述應(yīng)用中,日志一般分為以下個(gè)級別錯(cuò)誤信息警告信息一般信息調(diào)試信息跟蹤信息使用的作為內(nèi)部的日志框架,其僅僅是一個(gè)日志接口,在實(shí)際應(yīng)用中需要為該接口來指定相應(yīng)的日志實(shí)現(xiàn)。默認(rèn)的日志實(shí)現(xiàn)是,是自帶的日志包,此外當(dāng)然也支持這類很流行的日志實(shí)現(xiàn)。 showImg(https://segmentfault.com/img/remote/1460000014055501); 概述 Java應(yīng)用中...
摘要:想要看級別的信息,你需要在啟動時(shí)傳入這個(gè)系統(tǒng)屬性使用與日志現(xiàn)在我們可以試驗(yàn)并更換不同的日志實(shí)現(xiàn),但你的程序代碼可以保持不變。我們要做的是用另一個(gè)流行的日志實(shí)現(xiàn)來替換掉,比如。又一次,我們必須對我們選的每一個(gè)日志實(shí)現(xiàn)做配置。 使用slf4j庫作為你的Java應(yīng)用日志API層有很多好處,這里我會展示一小部分關(guān)于如何使用和配置它的例子。 你可以把slf4j想成一個(gè)Java的接口,然后你需要實(shí)...
閱讀 673·2021-11-24 09:39
閱讀 2342·2021-11-22 13:54
閱讀 2210·2021-09-23 11:46
閱讀 3254·2019-08-30 15:55
閱讀 2690·2019-08-30 15:54
閱讀 2414·2019-08-30 14:18
閱讀 1554·2019-08-29 14:15
閱讀 2743·2019-08-29 13:49