無(wú)責(zé)任的爛筆頭

          Concentrate & enjoy!
          posts - 3, comments - 15, trackbacks - 0, articles - 7
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          Words on Java Logging

          Posted on 2010-03-18 00:52 BZ 閱讀(870) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Misc


          •  關(guān)于Commons Logging

          Commons Logging庫(kù)包含了commons-logging-api.jarcommons-logging.jar. 查看這兩個(gè)文件的內(nèi)容, 你會(huì)發(fā)現(xiàn)它們的差別并不大: org.apache.commons.logging包下的內(nèi)容是相同的,差異的地方僅在org.apache.commons.logging.impl. 這兩個(gè)包內(nèi)容的描述可以參考官方網(wǎng)站:

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

           

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

           

          ps: commons-logging-api接口又被稱(chēng)為JCL(Jakarta Commons Logging). 實(shí)現(xiàn)JCL接口的庫(kù)除了Commons Logging自己外, 另一個(gè)很有名的就是SLF4J(http://www.slf4j.org/).


          • SLF4J性能最優(yōu)

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

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

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

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

           

          如果entry的轉(zhuǎn)換比較復(fù)雜, 就會(huì)比較耗時(shí). 特別是如果在上述例子中, debug levellog被禁用了, 這種轉(zhuǎn)換的開(kāi)銷(xiāo)則是完全沒(méi)有必要的(白白浪費(fèi)CPU和內(nèi)存). 當(dāng)然, 加上對(duì)相應(yīng)log level的啟用/禁用的判斷,然后再調(diào)用log方法, 也是可以避免這些開(kāi)銷(xiāo)的. 例如:

             if (logger.isDebugEnabled()) {

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

          }

           

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

          public void debug(String format, Object arg) {

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

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

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

              }

             }

           

           

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

          logger.debug("The entry is {}.", entry);  //直接調(diào)用, 無(wú)需判斷log level是否啟用. 簡(jiǎn)潔,高效

           

          需要說(shuō)明的是:

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

          l   SLF4J本身也是接口和實(shí)現(xiàn)分離的. 不是SLF4J的所有實(shí)現(xiàn)能具有性能上的優(yōu)勢(shì), 比如SLF4Jsimple實(shí)現(xiàn)版本就完全沒(méi)有性能上的優(yōu)化, 所以選擇SLF4J的實(shí)現(xiàn)前, 需要考察一下.

          • SpringSLF4J

          Spring從一開(kāi)始就依賴(lài)JCL(同時(shí)出于后向兼容的考慮, 在可以預(yù)見(jiàn)的未來(lái), 也會(huì)持續(xù)依賴(lài)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.

           

          可見(jiàn), Spring的開(kāi)發(fā)人員也意識(shí)到JCL的默認(rèn)實(shí)現(xiàn)沒(méi)有SLF4J優(yōu)秀. 幸運(yùn)的是,盡管Spring對(duì)JCL默認(rèn)實(shí)現(xiàn)的依賴(lài)如此嚴(yán)重, Spring中將其替換也不是不可能. 事實(shí)上, Spring官方就給出了一種方法, 這種方法本質(zhì)上是將SLF4J作為JCL的一種實(shí)現(xiàn):

          l   需要保留commons-logging-api.jar. 很多Spring Module都依賴(lài)JCL. 同時(shí)排除commons-logging.jar, 不要使用這種實(shí)現(xiàn).

          l   添加jcl-over-slf4j.jar. 這作為JCLSLF4J之間的bridge, 實(shí)際上就是采用SLF4J來(lái)實(shí)現(xiàn)JCL.

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

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


          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 旺苍县| 卢湾区| 金坛市| 苍溪县| 皋兰县| 永定县| 洛川县| 惠州市| 台中县| 土默特左旗| 奈曼旗| 乌拉特前旗| 临江市| 辽中县| 游戏| 乌兰县| 施甸县| 宁远县| 襄城县| 沭阳县| 正蓝旗| 收藏| 荣成市| 普洱| 绥宁县| 邯郸市| 芜湖市| 南木林县| 柘城县| 万源市| 高清| 义乌市| 扶绥县| 桃园市| 怀安县| 双鸭山市| 同江市| 赤峰市| 杨浦区| 和林格尔县| 怀宁县|