kapok

          垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            455 隨筆 :: 0 文章 :: 76 評(píng)論 :: 0 Trackbacks
          http://www.aygfsteel.com/jungleford/archive/2005/04/02/2760.html
           jungleford如是說 o_log4j.jpg

              用慣了VC的人剛接觸Java大概很不習(xí)慣代碼的調(diào)試,的確,在M$的大部分IDE都做得相當(dāng)出色,包括像VJ++這樣一直被Java程序員稱為是“垃圾”的類庫(記得以前在瀚海星云Java版提有關(guān)VJ問題的人是有可能被封的,^_^),它的開發(fā)工具在調(diào)試上都相當(dāng)容易。Java也有命令行方式的調(diào)試和IDE的調(diào)試,但現(xiàn)在的像JB這樣的玩意又是個(gè)龐然大物,低配置的機(jī)器可能就是個(gè)奢望,不像VC那樣。怎么辦呢,高手們說,“我的jdb用得賊熟練”,那我會(huì)報(bào)以景仰的目光,像我這樣的菜鳥基本上就沒使過jdb,還是老老實(shí)實(shí)在代碼里面System.out.println(...)。直到1996年一個(gè)叫做“歐洲安全電子市場”(E.U. SEMPER)的項(xiàng)目啟動(dòng),“調(diào)試”不再是一件“體力活”,而是一種軟件設(shè)計(jì)的藝術(shù),這個(gè)項(xiàng)目組開發(fā)的日志管理接口后來成為Apache Jakarta項(xiàng)目中的一員,它就是現(xiàn)在我們所熟悉的log4j。下面的文字將概要介紹與Java日志記錄相關(guān)的一些技術(shù),目的不是讓您放棄老土的System.out.println(...),而是說,在Java的世界里可以有許多種選擇,你今天覺得掌握了一件高級(jí)武器,明天可能就是“過時(shí)”的了,呵呵。

          始祖:System.out.println(...)

              為什么還是要一再提到它?畢竟我們的習(xí)慣不是那么容易改變的,而且System.out(別忘了還有System.err)是一個(gè)直接和控制臺(tái)打交道的PrintStream對(duì)象,是終端顯示的基礎(chǔ),高級(jí)的Logger要在終端顯示日志內(nèi)容,就必然會(huì)用到這個(gè)。一個(gè)小規(guī)模的程序調(diào)試,恰當(dāng)?shù)厥褂肧ystem.out.println(...)我認(rèn)為仍然是一種最方便最有效的方法,所以我們?nèi)园阉旁谧铋_始,以示不能“數(shù)典忘祖” :)

          不常用的關(guān)鍵字:assert

              assert對(duì)多數(shù)人來講可能還比較陌生,它也是一個(gè)調(diào)試工具,好像是J2SE 1.4才加進(jìn)來的東東,一種常見的用法是:
          assert (布爾表達(dá)式);

              當(dāng)表達(dá)式為true時(shí)沒有任何反映,如果為false系統(tǒng)將會(huì)拋出一個(gè)AssertionError。如果你要使用assert,在編譯時(shí)必須加上“-source 1.4”的選項(xiàng),在運(yùn)行時(shí)則要加上“-ea”選項(xiàng)。

          后生可畏:Java Logging API一瞥

              System.out.println(...)對(duì)于較高要求的用戶是遠(yuǎn)遠(yuǎn)不夠的,它還不是一個(gè)日志系統(tǒng),一個(gè)比較完善的日志系統(tǒng)應(yīng)當(dāng)有輸出媒介、優(yōu)先級(jí)、格式化、日志過濾、日志管理、參數(shù)配置等功能。伴隨J2SE 1.4一起發(fā)布的Java日志包java.util.logging適時(shí)地滿足了我們的初步需求,在程序中按一定格式顯示和記錄豐富的調(diào)試信息已經(jīng)是一件相當(dāng)easy的事情。

          1. 日志記錄器:Logger
              Logger是一個(gè)直接面向用戶的日志功能調(diào)用接口,從用戶的角度上看,它完成大部分日志記錄工作,通常你得到一個(gè)Logger對(duì)象,只需要使用一些簡單方法,譬如info,warning,log,logp,logrb等就能完成任務(wù),簡單到和System.out.println(...)一樣只用一條語句,但后臺(tái)可能在向控制臺(tái),向文件,向數(shù)據(jù)庫,甚至向網(wǎng)絡(luò)同時(shí)輸出該信息,而這個(gè)過程對(duì)用戶是完全透明的。
              在使用Logger之前,首先需要通過getLogger()或getAnonymousLogger()靜態(tài)方法得到一個(gè)Logger對(duì)象(想想看,這里是不是設(shè)計(jì)模式當(dāng)中的“工廠方法”的一個(gè)實(shí)實(shí)在在的應(yīng)用?可以參考一下Logger的源代碼,你就明白LogManager是“工廠類”而Logger是“產(chǎn)品類”,凡事都要學(xué)以致用嘛,呵呵)。這里我們需要了解的是Logger的“名字空間”(namespace)的概念:通常我們調(diào)試時(shí)需要清楚地知道某個(gè)變量是出現(xiàn)在什么位置,精確到哪個(gè)類的哪個(gè)方法,namespace就是這么個(gè)用處。我們用getLogger()得到Logger時(shí)需要指定這個(gè)Logger的名字空間,通常是一個(gè)包名,譬如“com.jungleford.test”等,如果是指定了namespace,那么將在一個(gè)全局對(duì)象LogManager中注冊這個(gè)namespace,Logger會(huì)基于namespace形成層次關(guān)系,譬如namespace為“com.jungleford”的Logger就是namespace為“com.jungleford.test”的Logger的父,后者調(diào)用getParent()方法將返回前者,如果當(dāng)前沒有namespace為“com.jungleford”的Logger,則查找namespace為“com”的Logger,要是按照這個(gè)鏈找不到就返回根Logger,其namespace為"",根Logger的父是null。從理論上說,這個(gè)namespace可以是任意的,通常我們是按所調(diào)試的對(duì)象來定,但如果你是使用getAnonymousLogger()方法產(chǎn)生的Logger,那它就沒有namespace,這個(gè)“匿名Logger”的父是根Logger。
              得到一個(gè)Logger對(duì)象后就可以記錄日志了,下面是一些常用的方法:
          finestfinerfineinfoconfigwarningsevere:簡潔的方法,輸出的日志為指定的級(jí)別。關(guān)于日志級(jí)別我們在后面將會(huì)詳細(xì)談到。

          log:不僅可以指定消息和級(jí)別,還可以帶一些參數(shù),甚至可以直接是一個(gè)LogRecord對(duì)象(這些參數(shù)是LogRecord對(duì)象的重要組成部分)。

          logp:更加精細(xì)了,不但具有l(wèi)og方法的功能,還可以不使用當(dāng)前的namespace,定義新的類名和方法名。

          enteringexiting:這兩個(gè)方法在調(diào)試的時(shí)候特別管用,用來觀察一個(gè)變量變化的情況,就如同我們在VC的調(diào)試狀態(tài)下watch一個(gè)變量,然后按F10,呵呵。

          2. 輸出媒介控制:Handler
              日志的意義在于它可以以多種形式輸出,尤其是像文件這樣可以長久保存的媒介,這是System.out.println(...)所無法辦到的。Logging API的Handler類提供了一個(gè)處理日志記錄(LogRecord,它是對(duì)一條日志消息的封裝對(duì)象)的接口,包括幾個(gè)已實(shí)現(xiàn)的API:
          ConsoleHandler:向控制臺(tái)輸出。

          FileHandler:向文件輸出。

          SocketHandler:向網(wǎng)絡(luò)輸出。

              這三個(gè)輸出控制器都是StreamHandler的子類,另外Handler還有一個(gè)MemoryHandler的子類,它有特殊的用處,我們在后面將會(huì)看到。在程序啟動(dòng)時(shí)默認(rèn)的Handler是ConsoleHandler,不過這個(gè)是可以配置的,下面會(huì)談到logging配置文件的問題。
              此外用戶還可以定制自己輸出控制器,繼承Handler即可,通常只需要實(shí)現(xiàn)Handler中三個(gè)未定義的抽象方法:
          publish:主要方法,把日志記錄寫入你需要的媒介。

          flush:清除緩沖區(qū)并保存數(shù)據(jù)。

          close:關(guān)閉控制器。

              通過重寫以上三個(gè)方法我們可以很容易就實(shí)現(xiàn)一個(gè)把日志寫入數(shù)據(jù)庫的控制器。

          3. 自定義輸出格式:Formatter
              除了可以指定輸出媒介之外,我們可能還希望有多種輸出格式,譬如可以是普通文本、HTML表格、XML等等,以滿足不同的查看需求。Logging API中的Formatter就是這樣一個(gè)提供日志記錄格式化方法接口的類。默認(rèn)提供了兩種Formatter:

          SimpleFormatter:標(biāo)準(zhǔn)日志格式,就是我們通常在啟動(dòng)一些諸如TomcatJBoss之類的服務(wù)器的時(shí)候經(jīng)常能在控制臺(tái)下看到的那種形式,就像這樣:
          2004-12-20 23:08:52 org.apache.coyote.http11.Http11Protocol init
          信息: Initializing Coyote HTTP/1.1 on http-8080

          2004-12-20 23:08:56 org.apache.coyote.http11.Http11Protocol init
          信息: Initializing Coyote HTTP/1.1 on http-8443

          XMLFormatter:XML形式的日志格式,你的Logger如果add了一個(gè)new XMLFormatter(),那么在控制臺(tái)下就會(huì)看到下面這樣的形式,不過更常用的是使用上面介紹的FileHandler輸出到XML文件中:
          <?xml version="1.0" encoding="GBK" standalone="no"?>
          <!DOCTYPE log SYSTEM "logger.dtd">
          <log>
          <record>
            <date>2004-12-20T23:47:56</date>
            <millis>1103557676224</millis>
            <sequence>0</sequence>
            <logger>Test</logger>
            <level>WARNING</level>
            <class>Test</class>
            <method>main</method>
            <thread>10</thread>
            <message>warning message</message>
          </record>

              與Handler類似,我們也可以編寫自己的格式化處理器,譬如API里沒有將日志輸出為我們可通過瀏覽器查看的HTML表格形式的Formatter,我們只需要重寫3個(gè)方法:
          format:格式化LogRecord中包含的信息。

          getHead:輸出信息的頭部。

          getTail:輸出信息的尾部。

          4. 定義日志級(jí)別:Level
              大家可能都知道Windows的“事件查看器”,里面有三種事件類型:“信息”、“警告”、“錯(cuò)誤”。這其實(shí)就是日志級(jí)別的一種描述。Java日志級(jí)別用Level類表示,一個(gè)日志級(jí)別對(duì)應(yīng)的是一個(gè)整數(shù)值,范圍和整型值的范圍是一致的,該整數(shù)值愈大,說明警戒級(jí)別愈高。Level有9個(gè)內(nèi)置的級(jí)別,分別是:
          類型 對(duì)應(yīng)的整數(shù)
          OFF 最大整數(shù)(Integer.MAX_VALUE
          SEVERE 1000
          WARNING 900
          INFO 800
          CONFIG 700
          FINE 500
          FINER 400
          FINEST 300
          ALL 最小整數(shù)(Integer.MIN_VALUE

              你也可以定義自己的日志級(jí)別,但要注意的是,不是直接創(chuàng)建Level的對(duì)象(因?yàn)樗臉?gòu)造函數(shù)是protected的),而是通過繼承Level的方式,譬如:
          class AlertLevel extends java.util.logging.Level
          {
            public AlertLevel()
            {
              super("ALERT", 950);
            }
          }
          ...
          Logger logger = Logger.getAnonymousLogger();
          logger.log(new AlertLevel(), "A dangerous action!");

              上面定義了一個(gè)高于WARNING但低于SEVERE的日志級(jí)別。
              于是可能有朋友會(huì)興沖沖地用以下的語句來記錄一個(gè)事件:
          Logger logger = Logger.getAnonymousLogger();
          logger.fine("Everything seems ok.");
          //或者是
          //logger.log(Level.FINE, "Everything seems ok.");

              但是一程序運(yùn)行,奇怪了,怎么沒有打印出任何消息呢?下一小節(jié)我們就來談這個(gè)問題。

          5. 日志過濾器:Filter
              所謂過濾器是控制哪些日志該輸出哪些不該輸出的一種組件。上面你寫的那條日志沒有能在控制臺(tái)顯示出來,是因?yàn)閘ogging API預(yù)先設(shè)定的缺省級(jí)別是INFO,也就是說只有級(jí)別不低于INFO(即其整數(shù)值不小于800)的日志才會(huì)被輸出,這個(gè)就是Filter的功能。所以我們可以看到SEVERE、WARNING、INFO以及上面我們定義的ALERT消息,但看不到FINE、FINER和FINEST消息。當(dāng)然,你盡可以用Logger的setLevel方法或者修改配置文件的方法(什么是配置文件,我們后面將會(huì)看到)來重新定義Logger輸出的最低級(jí)別。
              Filter不僅僅可以按日志級(jí)別過濾,你也可以定義自己的Filter,實(shí)現(xiàn)其中的isLoggable方法,隨便按照LogRecord攜帶的任何信息進(jìn)行過濾,譬如(順便復(fù)習(xí)一下匿名類,呵呵):
          Logger logger = Logger.getAnonymousLogger();
          logger.setFilter(new Filter()
          {
            public boolean isLoggable(LogRecord rec)
            {
              //從LogRecord里得到過濾信息
            }
          });

          6. 預(yù)定義參數(shù)
              LogManager是一個(gè)實(shí)現(xiàn)了Singleton模式的全局對(duì)象(由于是一個(gè)唯一的對(duì)象,LogManager需要是線程安全的),它管理著程序啟動(dòng)以后所有已注冊(包層次)或匿名的Logger,以及相關(guān)配置信息。這里的配置信息通常是從<JAVA_HOME>\jre\lib\logging.properties文件得到的。logging.properties對(duì)于logging API來說是一個(gè)很重要的文件,它的內(nèi)容一般是:

          ############################################################
          # Default Logging Configuration File
          #
          # You can use a different file by specifying a filename
          # with the java.util.logging.config.file system property.
          # For example java -Djava.util.logging.config.file=myfile
          ############################################################

          ############################################################
          # Global properties
          ############################################################

          # "handlers" specifies a comma separated list of log Handler
          # classes. These handlers will be installed during VM startup.
          # Note that these classes must be on the system classpath.
          # By default we only configure a ConsoleHandler, which will only
          # show messages at the INFO and above levels.
          handlers= java.util.logging.ConsoleHandler

          # To also add the FileHandler, use the following line instead.
          #handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

          # Default global logging level.
          # This specifies which kinds of events are logged across
          # all loggers. For any given facility this global level
          # can be overriden by a facility specific level
          # Note that the ConsoleHandler also has a separate level
          # setting to limit messages printed to the console.
          .level= INFO

          ############################################################
          # Handler specific properties.
          # Describes specific configuration info for Handlers.
          ############################################################

          # default file output is in user's home directory.
          java.util.logging.FileHandler.pattern = %h/java%u.log
          java.util.logging.FileHandler.limit = 50000
          java.util.logging.FileHandler.count = 1
          java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

          # Limit the message that are printed on the console to INFO and above.
          java.util.logging.ConsoleHandler.level = INFO
          java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

          ############################################################
          # Facility specific properties.
          # Provides extra control for each logger.
          ############################################################

          # For example, set the com.xyz.foo logger to only log SEVERE
          # messages:
          com.xyz.foo.level = SEVERE


              你可以通過修改這個(gè)配置文件來改變運(yùn)行時(shí)Logger的行為,譬如:.level定義的是上面所說的默認(rèn)輸出的最低日志級(jí)別;XXXHandler相關(guān)屬性定義了各種輸出媒介等等。
              這里比較有意思的是關(guān)于日志文件,也就是FileHandler,當(dāng)然,你可以在程序中創(chuàng)建一個(gè)FileHandler,然后添加到logger中:
          FileHandler fhd = new FileHandler("%h/java%u.log", 5000, 1, true);
          fhd.setLevel(Level.ALL);
          fhd.setFormatter(new XMLFormatter());
          logger.addHandler(fhd);

              這段代碼等價(jià)于上面logging.properties中的文字段:
          java.util.logging.FileHandler.pattern = %h/java%u.log
          java.util.logging.FileHandler.limit = 50000
          java.util.logging.FileHandler.count = 1
          java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

              這里的pattern代表用轉(zhuǎn)義字符定義的一個(gè)日志文件名:
          轉(zhuǎn)義字符串 含義
          %t 臨時(shí)目錄
          %h 用戶目錄,即系統(tǒng)屬性“user.home”對(duì)應(yīng)的值
          %g 一個(gè)隨機(jī)生成的數(shù)字,可以重復(fù)
          %u 一個(gè)隨機(jī)生成的非重復(fù)數(shù)字

              以上面的“%h/java%u.log”為例,在Windows 2000下代表日志文件可能就是:C:\Documents and Settings\Administrator\javax.log。這里x代表一個(gè)不重復(fù)的數(shù)字,如果是第一次,那么就是java0.log;如果在該目錄下已經(jīng)存在了一個(gè)java0.log的文件,那么logger就產(chǎn)生一個(gè)java1.log的新的日志文件。
              當(dāng)然,你可以在別的地方使用自己寫的配置文件,不過在啟動(dòng)程序時(shí)候需要指定java.logging.config.file屬性:
          java -Djava.logging.config.file=...

          7. 資源與本地化
              Logger里還有個(gè)方法叫logrb,可能初學(xué)者不太會(huì)用到。如果你安裝的JDK是國際版的,那么你將會(huì)看到在中文Windows平臺(tái)下日志輸出的INFO、WARNING顯示的是“信息”、“警告”等中文字樣。因?yàn)閘ogrb是一個(gè)和Java i18n/l10n相關(guān)的方法,你可以定義自己的“資源包”(Resource Bundle),然后在logrb方法中指定相應(yīng)的資源名稱,那么在輸出日志中你就能看到用自己定義的本地語言、時(shí)間等顯示的信息。如果你對(duì)i18n/l10n感興趣,可以參考Java Localization文檔


              了解以上組件后,我們回顧一個(gè)完整的日志處理的工作過程:
              程序啟動(dòng)日志服務(wù),創(chuàng)建Logger對(duì)象,LogManager按照namespace的層次結(jié)構(gòu)組織Logger,在同一個(gè)namespace里子Logger將繼承父Logger的屬性;同時(shí),LogManager從logging.properties中讀取相應(yīng)的屬性對(duì)Logger進(jìn)行初始化,如果在程序中設(shè)置了屬性則使用新的配置。當(dāng)應(yīng)用程序產(chǎn)生一條日志,Logger將創(chuàng)建一個(gè)LogRecord對(duì)象,該對(duì)象封裝了一條日志的全部信息。Logger需要根據(jù)當(dāng)前設(shè)置的Filter來判斷這條日志是否需要輸出,并將有用的日志傳給相應(yīng)的Handler處理,而Handler根據(jù)當(dāng)前設(shè)置的Formatter和Resource Bundle將日志消息轉(zhuǎn)換成一定的顯示格式,然后輸出到預(yù)定的媒介(控制臺(tái)、文件等)中去。整個(gè)過程大致如圖1所示:

          o_logging1.gif

          圖1

              前面我們在介紹Handler的時(shí)候提到過一個(gè)特殊的類叫MemoryHandler,這里我們要了解一下“Handler鏈”的概念,日志在輸出之前可能經(jīng)過多個(gè)Handler的處理,MemoryHandler在這種情況下就是一個(gè)中間角色,它維持一個(gè)內(nèi)存中的日志緩沖區(qū),當(dāng)日志沒有填滿緩沖區(qū)時(shí)就將全部日志送到下一個(gè)Handler,否則新進(jìn)來的日志將會(huì)覆蓋最老的那些日志,因此,使用MemoryHandler可以維護(hù)一定容量的日志,另外,MemoryHandler也可以不需要使用Formatter來進(jìn)行格式化,從而具有較高的效率。一個(gè)使用Handler鏈的例子如圖2所示:

          o_logging2.gif
          圖2

          青出于藍(lán):Apache Jakarta log4j日志工具包

              應(yīng)付日常的日志需求,J2SE的Logging API可以說已經(jīng)做得相當(dāng)出色了,但追求完美的開發(fā)人員可能需要可擴(kuò)展性更好的專業(yè)日志處理工具,log4j正是當(dāng)前比較流行的一個(gè)工具包,它提供更多的輸出媒介、輸出格式和配置選擇,你會(huì)發(fā)現(xiàn)原來在J2SE里一些仍需要自己手工構(gòu)建的功能在log4j當(dāng)中都已經(jīng)為你實(shí)現(xiàn)了。關(guān)于log4j我可能談得不會(huì)太多,可以看看文后所附的“參考資料”,網(wǎng)上也有很詳細(xì)的介紹,我在這里做的是一個(gè)對(duì)比,因?yàn)閘og4j和J2SE 1.4 Logging API的用法是很相似的,一些名稱不同的組件你會(huì)發(fā)現(xiàn)他們所處的地位其實(shí)是一樣的:
            J2SE 1.4中的類 log4j中的類
          日志記錄器 Logger Logger
          日志管理器 LogManager LogManager
          日志對(duì)象 LogRecord LoggingEvent
          輸出媒介控制 Handler Appender
          格式化 Formatter Layout
          級(jí)別 Level Level
          過濾器 Filter Filter

              log4j可以做到更精細(xì)更完善的控制,譬如J2SE里沒有現(xiàn)成向數(shù)據(jù)庫里寫日志的方法,但log4j卻有JDBCAppender,它甚至還能向GUI圖形界面(LF5Appender,一種以JTree方式顯示的層次結(jié)構(gòu))、Windows NT事件查看器(NTEventLogAppender)、UNIX的syslogd服務(wù)(SyslogAppender)、電子郵箱(SMTPAppender)、Telnet終端(TelnetAppender)、JMS消息(JMSAppender)輸出日志,牛吧;J2SE里默認(rèn)只能用%JAVA_HOME%\jre\lib\logging.properties做配置文件,但log4j卻可以在代碼中設(shè)置其它路徑下的properties文件或XML格式的配置文件。log4j的其它方面同樣很豐富,總之,log4j的最大的特點(diǎn)就是“靈活”,無論是Appender、Layout還是Configurator,你可以把日志輕松地弄成幾乎任何你想要的形式。

          框架與標(biāo)準(zhǔn):JSR議案

              從時(shí)間順序上講,log4j要比J2SE Logging API來得早,很多概念都是log4j先有的,但成為一個(gè)標(biāo)準(zhǔn),則是在JSR 47的形成。可能有人還不太了解JSR,這還要談到JCP,即“Java Community Process”,它是一個(gè)于1998年成立的旨在為Java技術(shù)制定民間標(biāo)準(zhǔn)的開放組織,你可以通過http://www.jcp.org/en/participation/membership申請成為它的付費(fèi)或免費(fèi)會(huì)員,JCP的主要工作就是制定和發(fā)布JSR(Java Specification Requests),JSR對(duì)于Java的意義就相當(dāng)于RFC對(duì)于網(wǎng)絡(luò)技術(shù)的意義,由于JCP會(huì)員們的集思廣益,使得JSR成為Java界的一個(gè)重要標(biāo)準(zhǔn)。JSR 47即“Logging API Specification”,制定了調(diào)試和日志框架,J2SE Logging API正是該框架的一個(gè)實(shí)現(xiàn)。由于種種原因,在JSR 47出來以前,log4j就已經(jīng)成為一項(xiàng)成熟的技術(shù),使得log4j在選擇上占據(jù)了一定的優(yōu)勢,但不能因此就說JSR 47是過時(shí)的規(guī)范,標(biāo)準(zhǔn)總是在發(fā)展的嘛!

          并不是全部:其它日志處理工具

              除了J2SE Logging API和log4j,日志處理方面還有別的技術(shù):Jakarta的commons組件項(xiàng)目中的JCL(Jakarta Commons Logging)是一個(gè)不錯(cuò)的選擇,它有點(diǎn)類似于GSS-API(通用安全服務(wù)接口)中的思想,其日志服務(wù)機(jī)制是可以替換的,也就是說既可以用J2SE Logging API也可以用log4j,但JCL對(duì)開發(fā)人員提供一致的接口,這一點(diǎn)相當(dāng)重要,組件可重用正是Jakarta Commons項(xiàng)目追求的一個(gè)目標(biāo);IBMJLog也是在J2SE Logging API之前推出的一個(gè)工具包,但JLog是一個(gè)商業(yè)產(chǎn)品。
              至于日志API的應(yīng)用那可就多了,現(xiàn)在哪個(gè)大一點(diǎn)的工具或平臺(tái)不用到日志模塊呢?Tomcat、JBoss……

              說了這么多,我們無非需要知道的一件事就是,“調(diào)試”也是一門學(xué)問。在我們一個(gè)勁地用System.out.println(...)而且用得很爽的時(shí)候,也應(yīng)該想想看,如何讓這樣一條菜鳥語句也能變得人性化和豐富多彩。

          參考資料

          posted on 2005-04-03 23:04 笨笨 閱讀(660) 評(píng)論(0)  編輯  收藏 所屬分類: J2EEHibernateAndSpringALLJ2SE
          主站蜘蛛池模板: 普格县| 莫力| 新和县| 永康市| 二手房| 东方市| 昌宁县| 嘉义县| 宣威市| 汉中市| 遂宁市| 南昌县| 佳木斯市| 宜城市| 郎溪县| 宁武县| 太仆寺旗| 资阳市| 开原市| 高陵县| 台山市| 湘西| 临泉县| 拉萨市| 义马市| 子长县| 霍林郭勒市| 岑巩县| 昌吉市| 清新县| 阳新县| 城固县| 太谷县| 郯城县| 永嘉县| 靖江市| 女性| 台北市| 那坡县| 鄢陵县| 舟山市|