日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

读logback源码系列文章(五)——Appender --转载

發布時間:2025/4/5 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 读logback源码系列文章(五)——Appender --转载 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文地址:http://kyfxbl.iteye.com/blog/1173788

明天要帶老婆出國旅游幾天,所以這段時間暫時都更新不了博客了,臨走前再最后發一貼?

上一篇我們說到Logger類的info()方法通過層層調用,最后委托Appender來記錄日志,這篇博客我們就接著說一下,Appender組件是怎么記錄日志的?

實際上Appender可能是logback框架中最重要的組件之一,雖然Logger是記錄日志的接口,但是如果一個Logger沒有關聯到任何Appender的話,那么這個Logger就無法記錄任何信息。此外雖然logback提供了很多擴展點,但是在應用中,我們可能很少會擴展filter,很少擴展layout和encoder,但是我們擴展Appender的機會卻是很多的?

老規矩,首先上圖,看一下Appender的大圖景,這里要說明的是,實現Appender接口有2個base類,一個是AppenderBase,另一個是UnsynchronizedAppenderBase,這2個類非常接近,80%以上的代碼都是相同的。如果我們自己要自定義Appender的話,只要寫一個類繼承自這2個base類就好?



首先是有一個Appender接口,然后如上文所說,UnsynchronizedAppenderBase類實現了這個接口,但是它本身是一個抽象類,需要繼承它才能得到真正的實現類。Appender接口繼承了FilterAttachable接口,而UnsynchronizedAppenderBase類持有一個FilterAttachableImpl類,委托這個類來實現FilterAttachable接口里定義的方法?

然后OutputStreamAppender是繼承自UnsynchronizedAppenderBase的Appender實現類,雖然它已經不是抽象類了,但是實際也是不能直接使用的,它的實現類就是最常見的ConsoleAppender和FileAppender?

只要自己使用過logback的朋友都知道,appender元素下面還需要配置encoder元素,這里的Encoder接口就是對應這個encoder元素的,因為其實Appender組件還不是最終實際記錄日志信息的組件,它要委托encoder組件來完成LoggingEvent的格式化和記錄?

介紹完了大體的結構,我們接下來就看看,從Appender接口的doAppend()方法,是怎么一步步地最終記錄日志的

首先是UnsynchronizedAppenderBase里面的doAppend()方法,它主要是記錄了Status狀態,然后檢查Appender上的Filter是否滿足過濾條件,最后再調用實現子類的appender()方法。很眼熟是嗎,這里用到了一個設計模式——模板方法?

Java代碼??
  • public?void?doAppend(E?eventObject)?{??
  • ????//?WARNING:?The?guard?check?MUST?be?the?first?statement?in?the??
  • ????//?doAppend()?method.??
  • ????????
  • ????//?prevent?re-entry.??
  • ????if?(Boolean.TRUE.equals(guard.get()))?{??
  • ??????return;??
  • ????}??
  • ??
  • ????try?{??
  • ??????guard.set(Boolean.TRUE);??
  • ??
  • ??????if?(!this.started)?{??
  • ????????if?(statusRepeatCount++?<?ALLOWED_REPEATS)?{??
  • ??????????addStatus(new?WarnStatus(??
  • ??????????????"Attempted?to?append?to?non?started?appender?["?+?name?+?"].",??
  • ??????????????this));??
  • ????????}??
  • ????????return;??
  • ??????}??
  • ??
  • ??????if?(getFilterChainDecision(eventObject)?==?FilterReply.DENY)?{??
  • ????????return;??
  • ??????}??
  • ??
  • ??????//?ok,?we?now?invoke?derived?class'?implementation?of?append??
  • ??????this.append(eventObject);??
  • ??
  • ????}?catch?(Exception?e)?{??
  • ??????if?(exceptionCount++?<?ALLOWED_REPEATS)?{??
  • ????????addError("Appender?["?+?name?+?"]?failed?to?append.",?e);??
  • ??????}??
  • ????}?finally?{??
  • ??????guard.set(Boolean.FALSE);??
  • ????}??
  • ??}??
  • ??
  • ??abstract?protected?void?append(E?eventObject);??

  • 上面的代碼非常簡單,就不用說了,我們就直接看看實現類的append()方法是怎么實現的,這里我們選擇OutputStreamAppender實現類?

    Java代碼??
  • @Override??
  • ??protected?void?append(E?eventObject)?{??
  • ????if?(!isStarted())?{??
  • ??????return;??
  • ????}??
  • ??
  • ????subAppend(eventObject);??
  • ??}??

  • 首先檢查一下這個Appender是否已經啟動,如果沒啟動就直接返回,如果已經啟動,則又進入一個subAppend()方法?

    Java代碼??
  • /**?
  • ???*?Actual?writing?occurs?here.?
  • ???*?<p>?
  • ???*?Most?subclasses?of?<code>WriterAppender</code>?will?need?to?override?this?
  • ???*?method.?
  • ???*??
  • ???*?@since?0.9.0?
  • ???*/??
  • ??protected?void?subAppend(E?event)?{??
  • ????if?(!isStarted())?{??
  • ??????return;??
  • ????}??
  • ????try?{??
  • ??????//?this?step?avoids?LBCLASSIC-139??
  • ??????if?(event?instanceof?DeferredProcessingAware)?{??
  • ????????((DeferredProcessingAware)?event).prepareForDeferredProcessing();??
  • ??????}??
  • ??????//?the?synchronization?prevents?the?OutputStream?from?being?closed?while?we??
  • ??????//?are?writing.?It?also?prevents?multiple?thread?from?entering?the?same??
  • ??????//?converter.?Converters?assume?that?they?are?in?a?synchronized?block.??
  • ??????synchronized?(lock)?{??
  • ????????writeOut(event);??
  • ??????}??
  • ????}?catch?(IOException?ioe)?{??
  • ??????//?as?soon?as?an?exception?occurs,?move?to?non-started?state??
  • ??????//?and?add?a?single?ErrorStatus?to?the?SM.??
  • ??????this.started?=?false;??
  • ??????addStatus(new?ErrorStatus("IO?failure?in?appender",?this,?ioe));??
  • ????}??
  • ??}??

  • 這個方法居然什么事也不干。。做了一些檢查以后,又進入writeOut()方法。。。?

    Java代碼??
  • protected?void?writeOut(E?event)?throws?IOException?{??
  • ????this.encoder.doEncode(event);??
  • ??}??

  • writeOut()方法委托配置給它的Encoder組件來記錄?

    Java代碼??
  • public?void?doEncode(E?event)?throws?IOException?{??
  • ????String?txt?=?layout.doLayout(event);??
  • ????outputStream.write(convertToBytes(txt));??
  • ????outputStream.flush();??
  • ??}??

  • 到這里,終于完了。Encoder組件又委托其Layout組件來將LoggingEvent進行格式化,返回一個String,然后通過OutputStream.write()方法,把格式化之后的日志信息寫到目的地?

    耐心看到這里的朋友,可能已經有點被繞暈了,怎么Appender需要這么麻煩嗎?其實我們這里說的只是ConsoleAppender的doAppend()全流程,并不是所有Appender都這么復雜的,當然也有一些更復雜的。。?

    下面看一個簡單的Appender,就是我自己寫的MyAppender?

    Java代碼??
  • public?class?MyAppender?extends?AppenderBase<LoggingEvent>?{??
  • ??
  • ????@Override??
  • ????protected?void?append(LoggingEvent?eventObject)?{??
  • ????????System.out.println(eventObject.getMessage());??
  • ????}??
  • ??
  • }??

  • 好吧,非常簡單是不是,如果把這個Appender配置到logback.xml中,那么當Logger.info()調用的時候,就會先走進AppenderBase類的doAppend()方法里,進行Filter校驗等等,然后進入MyAppender的append()方法,不做其他的操作,直接把message給打印到Console上。當然,由于這個類是極度簡化的,沒有Encoder和Layout,也就沒辦法控制輸出日志的時間,也沒有辦法對%thread等標記進行解析處理了。但是這個類可能可以很清晰地表達出,Appender組件是怎么工作的:由AppenderBase類來調用Filter鏈,然后由Appender實現類來委托Encoder解析LoggingEvent,再輸出到目的地?

    這篇博客到這里就結束了。到目前為止,5篇博客是這樣的:?
    1、首先介紹logback怎么和slf4j對接?
    2、然后介紹logback的LoggerFactory,也就是LoggerContext是怎么創建的?
    3、接下來介紹LoggerFactory怎么創建Logger?
    4、然后是Logger怎么記錄日志,這其中涉及了級聯調用Appender,和調用TurboFilter來過濾的問題?
    5、本篇博客又以最常見的ConsoleAppender為例子,介紹了Appender組件怎么把日志信息輸出到目的地?

    下一篇博客的主題有多種分支,可以再講講DBAppender和FileAppender是怎么記錄日志的,作為這篇博客的補充,加深理解;也可以繼續深入下去,說說Encoder和Layout組件;或者回頭介紹一下logback是怎么初始化的?

    等我陪老婆旅游回來,再繼續更新本系列

    轉載于:https://www.cnblogs.com/davidwang456/p/4466936.html

    總結

    以上是生活随笔為你收集整理的读logback源码系列文章(五)——Appender --转载的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。