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

關于slf4j_log4j2源碼學習心得

 更新時間:2021年12月22日 10:34:17   作者:會灰翔的灰機  
這篇文章主要介紹了slf4j_log4j2源碼學習心得,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

日志工廠獲取Logger

slf4j_getLogger.jpg

獲取日志工廠_getILoggerFactory_

執(zhí)行初始化performInitialization

綁定工廠bind

查找可能被綁定的StaticLoggerBinder類路徑findPossibleStaticLoggerBinderPathSet

如果LoggerFactory類加載器為空則使用System類加載器,如果System類加載器為空則使用Bootstrap類加載器加載讀取org/slf4j/impl/StaticLoggerBinder.class類資源路徑

如果LoggerFactory類加載器不為空,使用loggerFactoryClassLoader類加載器讀取org/slf4j/impl/StaticLoggerBinder.class類資源路徑

獲取StaticLoggerBinder單例_SINGLETON_

打印實際綁定的StaticLoggerBInder實例,標識初始化成功

此時日志工廠已經(jīng)完成初始化,創(chuàng)建日志代替者工廠SubstituteLoggerFactory,獲取替代者工廠中的Loggers遍歷其名稱從日志工廠中獲取相應的Logger,將Logger設置為替代者委派對象setDelegate

重新播放替代者工廠事件隊列中的事件

清楚替代者工廠事件隊列,日志列表

使用StaticLoggerBinder獲取日志工廠,log4j2的綁定著實現(xiàn)返回Log4jLoggerFactory

日志工廠中獲取Logger,先獲取日志上下文,從日志上下文中獲取Logger

根據(jù)日志配置屬性log4j2.loggerContextFactory獲取日志上下文工廠

不存在日志上下文工廠配置則使用ProviderUtil提供者工具類讀取SPI配置默認為Log4jContextFactory

日志上下文工廠構(gòu)造器中創(chuàng)建日志上下文選擇器createContextSelector,根據(jù)Log4jContextSelector屬性配置獲取日志上下文選擇器實現(xiàn),假定為異步實現(xiàn):AsyncLoggerContextSelector

日志上下文工廠使用日志上下文選擇器創(chuàng)建日志上下文AsyncLoggerContext,日志上下文構(gòu)造器中創(chuàng)建AsyncLoggerDisruptor

如果日志上下文處于初始化狀態(tài),啟動日志上下文,啟動日志上下文中的loggerDisruptor

啟動Disruptor

計算ringBufferSize,如果啟用了Threadlocals(log4j2.enable.threadlocals)則默認4k,否則256k,讀取AsyncLogger.RingBufferSize屬性配置;如果size小于128則使用128修正

創(chuàng)建等待策略,如果屬性名稱以AsyncLogger.開頭,讀取AsyncLogger.Timeout,否則讀取AsyncLoggerConfig.Timeout配置的超時時間,默認為10毫秒;讀取AsyncLogger.WaitStrategy屬性配置的策略類型,默認為TIMEOUT,根據(jù)類型創(chuàng)建等待策略,默認為超時類型:TimeoutBlockingWaitStrategy

創(chuàng)建單線程線程池_newSingleThreadExecutor_

創(chuàng)建異步隊列滿的處理策略AsyncQueueFullPolicyFactory.create,讀取log4j2.AsyncQueueFullPolicy策略配置,默認策略為同步阻塞DefaultAsyncQueueFullPolicy,Discard類型為DiscardingAsyncQueueFullPolicy,否則讀取用戶自定義策略,獲取類路徑上的AsyncQueueFullPolicy實現(xiàn)類

創(chuàng)建Disruptor實例

為Disruptor實例綁定ExceptionHandler,讀取AsyncLogger.ExceptionHandler屬性配置加載實現(xiàn)類,默認為AsyncLoggerDefaultExceptionHandler

為Disruptor實例綁定事件handler:RingBufferLogEventHandler

啟動Disruptor

提交線程BatchEventProcessor至線程池

向序列屏障提交序列號申請并等待,等待策略默認為Timeout,超時處理后進行線程yield資源釋放

獲取到有效序列號根據(jù)序列號獲取數(shù)據(jù)RingBufferLogEvent

回調(diào)事件handle實例記錄日志RingBufferLogEventHandler.onEvent

執(zhí)行事件RingBufferLogEvent.execute(異步寫日志)

啟動父類日志上下文LoggerContext.start(),重新加載配置reconfigure,設置配置setConfiguration,啟動配置config.start();

map.putIfAbsent("contextName", contextName);
config.start();
this.configuration = config;
  • 由日志上下文中獲取日志getLogger,不存在則創(chuàng)建日志AsyncLogger
  • 返回異步日志實例

日志輸出Logger.info

slf4j_AsyncLogger.jpg

日志打印logger.info

MessageFactory2將字符串日志封裝為Message實例:ParameterizedMessageFactory.newMessage

從緩存中獲取RingBuffer日志事件轉(zhuǎn)換器:AsyncLogger.logWithThreadLocalTranslator.getCachedTranslator

初始化RingBuffer日志事件轉(zhuǎn)換器:AsyncLogger.initTranslator,RingBufferLogEventTranslator.setBasicValues設置基礎值

發(fā)布日志事件轉(zhuǎn)換器:RingBufferLogEventTranslator

異步日志Disruptor嘗試發(fā)布tryPublish

Disruptor獲取RingBuffer嘗試發(fā)布

轉(zhuǎn)換器將日志數(shù)據(jù)轉(zhuǎn)換為日志事件:RingBufferLogEventTranslator.translateTo

根據(jù)序號sequence獲取對應的事件實例RingBufferLoggerEvent并將轉(zhuǎn)換器中的數(shù)據(jù)寫入RingBufferLoggerEvent.setValues

發(fā)布消息序列號MultiProducerSequencer

等待策略發(fā)送喚醒信號TimeoutBlockingWaitStrategy.signalAllWhenBlocking

異步日志寫入

slf4j_writeLogger.jpg

BatchEventProcessor.eventHandler.onEvent->RingBufferLogEventHandler.onEvent->執(zhí)行事件RingBufferLogEvent.execute

執(zhí)行異步日志寫入當前事件消息actualAsyncLog(this)

從可靠性策略工廠中獲取可靠性策略,根據(jù)參數(shù)配置獲?。簂og4j.ReliabilityStrategy,默認AwaitCompletion:AwaitCompletionReliabilityStrategy,寫入日志strategy.log(AsyncLogger, event);

可靠性策略獲取活躍的LoggerConfig,如果沒取到,遞歸AsyncLogger的next節(jié)點獲取

LoggerConfig寫入日志log,走過濾器鏈過濾事件之后處理事件processLogEvent

調(diào)用Appender:callAppenders

調(diào)用AsyncLoggerConfigDisruptor的tryEnqueue,準備事件,將事件封裝為Log4jLogEvent綁定至Log4jEventWrapper.event然后嘗試發(fā)布

事件handle處理事件Log4jEventWrapperHandler.onEvent

異步調(diào)用Appender:asyncCallAppenders,調(diào)用父類callAppenders

遍歷AppenderControl調(diào)用callAppender,調(diào)用callAppenderPreventRecursion

嘗試appender tryCallAppender

調(diào)用Appender追加方法append追加日志,假定為RollingRandomAccessFileAppender配置實現(xiàn),調(diào)用父類tryAppend

讀取log4j2.enable.direct.encoders配置是否直接編譯,默認為true,直接編譯事件directEncodeEvent

獲取布局Layout編譯事件encode,假定為PatternLayout配置實現(xiàn)

如果布局的事件序列化類型eventSerializer不是Serializer2,調(diào)用父類encode,否則繼續(xù)

從threadlocal中獲取StringBuilder,不存在則創(chuàng)建,如果超出最大值則trim至最大值,最大值配置:log4j.layoutStringBuilder.maxSize,默認為2*1024,stringbuilder設置length為0

將事件序列化后放入StringBuilder:toSerializable

獲取StringBuilder編譯器編譯StringBuilder至ByteBufferDestination

manager刷新flush,刷新至目的地,假定為RollingRandomAccessFileManager配置實現(xiàn),寫入目標文件

至此寫入日志完成

異步日志上下文選擇

通過管理器獲取日志上下文LogManager.getContext(false)

public static LoggerContext getContext(final boolean currentContext) {
    // TODO: would it be a terrible idea to try and find the caller ClassLoader here?
    try {
        return factory.getContext(FQCN, null, null, currentContext, null, null);
    } catch (final IllegalStateException ex) {
        LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
        return new SimpleLoggerContextFactory().getContext(FQCN, null, null, currentContext, null, null);
    }
}

上下文根據(jù)選擇器選擇獲取,我們假定是AsyncLoggerContextSelector類型,獲取方式是其超類ClassLoaderContextSelector提供getContext實現(xiàn)

可以看到只傳了一個參數(shù)currentContext,如果為true則會根據(jù)ContextAnchor.THREAD_CONTEXT當前線程對應的上下文,如果為空則獲取默認的上下文DEFAULT_CONTEXT,如果默認為空則會創(chuàng)建并緩存

如果currentContext為false則會選擇一個最匹配的恰當?shù)纳舷挛姆祷兀绻鸆lassLoader不為空則按照指定的ClassLoader定位選擇locateContext。否則按照當前的調(diào)用類的classloader進行定位選擇

public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext,
            final URI configLocation) {
        if (currentContext) {
            final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
            if (ctx != null) {
                return ctx;
            }
            return getDefault();
        } else if (loader != null) {
            return locateContext(loader, configLocation);
        } else {
            final Class<?> clazz = StackLocatorUtil.getCallerClass(fqcn);
            if (clazz != null) {
                return locateContext(clazz.getClassLoader(), configLocation);
            }
            final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get();
            if (lc != null) {
                return lc;
            }
            return getDefault();
        }
    }

locateContext定位選擇日志上下文

根據(jù)classloader的hashcode值獲取對應的日志上下文,異步選擇器實現(xiàn)添加了前綴

@Override
    protected String toContextMapKey(final ClassLoader loader) {
        // LOG4J2-666 ensure unique name across separate instances created by webapp classloaders
        return "AsyncContext@" + Integer.toHexString(System.identityHashCode(loader));
    }

如果對應的日志上下文為空則創(chuàng)建并緩存

如果configLocation為空則遍歷classloader的父classloader獲取對應的日志上下文返回,如果不存在則繼續(xù)創(chuàng)建

如果configLocation不為空則直接根據(jù)configLocation創(chuàng)建日志上下文并按照classloader的hashcode值拼接的名稱緩存至CONTEXT_MAP

如果CONTEXT_MAP緩存存在對應的日志上下文,并且不為空,則會判斷configLocation是否一致equals方法,如果不一致則更新后返回

如果CONTEXT_MAP緩存存在對應的日志上下文,并且為空,則創(chuàng)建日志上下文以及日志上下文的弱引用WeakReference并緩存至

總結(jié)

對于異步日志,如果includeLocation沒有指定,默認是關閉的狀態(tài),也就是不會記錄日志調(diào)用時的堆棧位置信息:LoggerConfig.includeLocation。

如果記錄日志時存在Throwable對象,則會記錄至RingBufferLogEventTranslator.thrown。

thrown在日志事件反序列化后為null,thrownProxy可能不為null,thrownProxy是thrown的代理,即使用thrown為入?yún)?gòu)造的代理實例

    // Note: for asynchronous loggers, includeLocation default is FALSE,
    // for synchronous loggers, includeLocation default is TRUE.
    protected static boolean includeLocation(final String includeLocationConfigValue) {
        if (includeLocationConfigValue == null) {
            final boolean sync = !AsyncLoggerContextSelector.isSelected();
            return sync;
        }
        return Boolean.parseBoolean(includeLocationConfigValue);
    }

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • JAVA設計模式之備忘錄模式原理與用法詳解

    JAVA設計模式之備忘錄模式原理與用法詳解

    這篇文章主要介紹了JAVA設計模式之備忘錄模式,簡單說明了備忘錄模式的概念、原理并結(jié)合實例形式分析了java備忘錄模式的具體定義及使用方法,需要的朋友可以參考下
    2017-08-08
  • 圖文詳解SpringBoot中Log日志的集成

    圖文詳解SpringBoot中Log日志的集成

    這篇文章主要給大家介紹了關于SpringBoot中Log日志的集成的相關資料,文中通過實例代碼以及圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2021-12-12
  • Java編程實現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法

    Java編程實現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法

    這篇文章主要介紹了Java編程實現(xiàn)判斷網(wǎng)上鄰居文件是否存在的方法,涉及Java針對路徑轉(zhuǎn)換及字符串操作的相關技巧,需要的朋友可以參考下
    2015-10-10
  • Apache?Arrow?Parquet存儲與使用

    Apache?Arrow?Parquet存儲與使用

    這篇文章主要為大家介紹了Apache?Arrow?Parquet存儲與使用原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • redis setIfAbsent和setnx的區(qū)別與使用說明

    redis setIfAbsent和setnx的區(qū)別與使用說明

    這篇文章主要介紹了redis setIfAbsent和setnx的區(qū)別與使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java實現(xiàn)圖形卡片排序游戲

    java實現(xiàn)圖形卡片排序游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)圖形卡片排序游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Springboot獲取文件內(nèi)容如何將MultipartFile轉(zhuǎn)File

    Springboot獲取文件內(nèi)容如何將MultipartFile轉(zhuǎn)File

    本文給大家介紹Springboot獲取文件內(nèi)容,將MultipartFile轉(zhuǎn)File方法,本文結(jié)合示例代碼給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2024-01-01
  • Java判斷字節(jié)流是否是 UTF8編碼方法示例

    Java判斷字節(jié)流是否是 UTF8編碼方法示例

    這篇文章主要我大家介紹了Java判斷字節(jié)流是否是 UTF8編碼方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • OpenFeign實現(xiàn)遠程調(diào)用

    OpenFeign實現(xiàn)遠程調(diào)用

    這篇文章主要為大家詳細介紹了OpenFeign實現(xiàn)遠程調(diào)用,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • SpringBoot自定義start詳細圖文教程

    SpringBoot自定義start詳細圖文教程

    這篇文章主要給大家介紹了關于SpringBoot自定義start的相關資料,主要講述如何自定義start,實現(xiàn)一些自定義類的自動裝配,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-11-11

最新評論