無責任的爛筆頭

          Concentrate & enjoy!
          posts - 3, comments - 15, trackbacks - 0, articles - 7
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          Words on Java Logging

          Posted on 2010-03-18 00:52 BZ 閱讀(874) 評論(0)  編輯  收藏 所屬分類: Misc


          •  關于Commons Logging

          Commons Logging庫包含了commons-logging-api.jarcommons-logging.jar. 查看這兩個文件的內容, 你會發現它們的差別并不大: org.apache.commons.logging包下的內容是相同的,差異的地方僅在org.apache.commons.logging.impl. 這兩個包內容的描述可以參考官方網站:

          http://commons.apache.org/logging/guide.html#commons-logging.jar

           

          簡單地說, commons-logging-api.jar僅包含定義接口的類, commons-logging.jar是其的一種實現。由于commons-logging.jar實現類較少且簡單, 為了方便部署, 于是將commons-logging-api.jar中對于接口的定義也一并打包在commons-logging.jar. 這樣一來, 對于要采用commons-logging為實現類的應用程序,只要讓commons-logging.jarclasspath中就好。類似地, 如果不計劃使用commons-logging為實現(但采用commons-logging-api的另一種實現),則需要將commons-logging-api.jar放到classpath, commons-logging.jar則是不需要(也不能添加).

           

          ps: commons-logging-api接口又被稱為JCL(Jakarta Commons Logging). 實現JCL接口的庫除了Commons Logging自己外, 另一個很有名的就是SLF4J(http://www.slf4j.org/).


          • SLF4J性能最優

          SLF4J的官方網站指明SLF4J擁有絕佳的性能. http://www.slf4j.org/faq.html#logging_performance. SLF4J提供的API甚至達到其它API性能的30:

          … the second form will outperform the first form by a factor of at least 30, in case of a disabled logging statement …

          性能的提升關鍵在于減少將對象(特別是非常復雜的對象且其toString()方法實現得比較耗時)轉換為String的開銷. JCL定義的log方法(trace, debug, info, warnerror)只包含一個Object類型的參數. 這樣, 執行這些方法之前就必須將所有要log的東西轉化為一個Object類型的對象(通常是String), 例如:

          logger.debug("The new entry is "+entry+".");

           

          如果entry的轉換比較復雜, 就會比較耗時. 特別是如果在上述例子中, debug levellog被禁用了, 這種轉換的開銷則是完全沒有必要的(白白浪費CPU和內存). 當然, 加上對相應log level的啟用/禁用的判斷,然后再調用log方法, 也是可以避免這些開銷的. 例如:

             if (logger.isDebugEnabled()) {

               logger.debug("The new entry is "+entry+".");

          }

           

          在這種情況下, 轉換的開銷就被避免了.在上述代碼中, 對于log level的啟用/禁用的判斷實際上是執行了兩次: 一次是在if語句中的顯式調用, 另一次則是log方法內部在做真正的log動作之前進行了調用. 對于log level的啟用/禁用的判斷產生的開銷相當小, 很多時候是可以忽略不計的. 但是, SLF4J比較計較, 它認為仍然有一次調用是沒有必要的. SLF4J解決這個問題的方法也很簡單: 利用與String.format()類似的方法, 需要的參數無需轉換, 而是作為函數的參數傳入, 函數在實現時, 先判斷log level是否被啟用. 如果沒有, 直接返回. 否則, 轉換, 然后log. 從這種實現思路可以知道, SLF4J需要定義另一套API, JCL所有log方法的基礎上增加一個(或多個)用來表示傳入對象的參數。例如:

          public void debug(String format, Object arg) {

              if (logger.isLoggable(Level.FINE)) {  //判斷log level的啟用情況

                String msgStr = MessageFormatter.format(format, arg);  //format,轉化

                log(SELF, Level.FINE, msgStr, null);  //log動作

              }

             }

           

           

          這下, 調用這樣的API自然就能在性能上勝人一籌了:

          logger.debug("The entry is {}.", entry);  //直接調用, 無需判斷log level是否啟用. 簡潔,高效

           

          需要說明的是:

          l   log方法的第一個參數(format), SLF4J自定義的, 不是String.format()所支持的那些. SLF4Jformat更簡單.

          l   SLF4J本身也是接口和實現分離的. 不是SLF4J的所有實現能具有性能上的優勢, 比如SLF4Jsimple實現版本就完全沒有性能上的優化, 所以選擇SLF4J的實現前, 需要考察一下.

          • SpringSLF4J

          Spring從一開始就依賴JCL(同時出于后向兼容的考慮, 在可以預見的未來, 也會持續依賴JCL), 而不是SLF4J. Spring的官方文檔中可以看到這樣的敘述:

          If we could turn back the clock and start Spring now as a new project it would use a different logging dependency. The first choice would probably be the Simple Logging Facade for Java (SLF4J), which is also used by a lot of other tools that people use with Spring inside their applications.

           

          可見, Spring的開發人員也意識到JCL的默認實現沒有SLF4J優秀. 幸運的是,盡管SpringJCL默認實現的依賴如此嚴重, Spring中將其替換也不是不可能. 事實上, Spring官方就給出了一種方法, 這種方法本質上是將SLF4J作為JCL的一種實現:

          l   需要保留commons-logging-api.jar. 很多Spring Module都依賴JCL. 同時排除commons-logging.jar, 不要使用這種實現.

          l   添加jcl-over-slf4j.jar. 這作為JCLSLF4J之間的bridge, 實際上就是采用SLF4J來實現JCL.

          l   添加slf4j-api.jar. 這是SLF4J的接口包.

          l   添加SLF4J的一種實現(以及這種實現需要的其他包). 比如計劃使用log4j, 則添加slf4j-log4j12.jar(以及log4j.jar).


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 工布江达县| 揭西县| 香港| 衡阳市| 开化县| 朝阳区| 万州区| 镇巴县| 新蔡县| 紫阳县| 漳浦县| 广东省| 怀安县| 陆河县| 邛崃市| 嘉义市| 墨玉县| 菏泽市| 淄博市| 罗源县| 安吉县| 肥城市| 麻城市| 仙游县| 唐海县| 托克逊县| 陇川县| 安多县| 南安市| 永济市| 且末县| 德安县| 七台河市| 孟村| 钟祥市| 元江| 南通市| 黄平县| 星座| 汝州市| 华蓥市|