本系列轉載自?http://blog.csdn.net/haitao111313/article/category/1179996?
?
只要實現Logger就能有一個自己的日志記錄器,其中setContainer是把日志記錄器跟具體的容器關聯,setVerbosity是設置日志的級別,log是具體的日志記錄函數。FATAL,ERROR,WARNING,INFORMATION,DEBUG代表日志記錄的五個級別,看單詞就能明白意思。這里主要講解一下FileLogger類,這是Tomcat的其中一個日志記錄器,它把日志記錄在一個文件中,FileLogger的啟動方法和關閉僅僅是出發一個生命周期事件,并不做其他的事情:
這里有一行代碼sm.getString("fileLogger.alreadyStarted"),牽涉到國際化的問題,等下再說這個問題。現在先看日志記錄器,FileLogger的open方法打開一個文件用來記錄日志:
這里得到一個PrintWriter的輸出流writer,在log方法記錄日志的時候會用到,下面看log方法:
writer.println把時間和日志信息寫進日志文件中。當然,這個日志記錄器一般是給Tomcat自己用的,我們也可以實現Logger接口,然后重寫它的open方法(打開我們自己的日志文件)和log方法(用來在我們自己的日志文件中記錄日志信息)。
分別表示三種語言的屬性文件。LocalStrings.properties屬性文件是默認的屬性文件。看LocalStrings.properties屬性中的內容:
ResourceBundle類通過getBundle方法獲取,參數是屬性文件的包名家名字前綴,上面就是包名加LocalStrings。通過getString(String key)方法獲取屬性文件中的參數:
現在來看代碼sm.getString("fileLogger.alreadyStarted"),sm是StringManager的實例,在FileLogger中已經初始化:
代碼很好理解,如果已經有StringManager實例了就直接從managers(這是一個Hashtable)中拿,沒有就新建一個。看StringManager的構造方法:
看到我們熟悉的ResourceBundle類了,根據上面的講解,ResourceBundle.getBundle(bundleName)能拿到默認的屬性文件,也就是上面的LocalStrings.properties文件。再回到sm.getString("fileLogger.alreadyStarted"),看sm的getString方法:
重點是budle.getString(key),這句代碼能拿到LocalStrings.properties文件的key屬性(這里是fileLogger.alreadyStarted)的值,即File Logger has already been started。這樣我們便能定義多個屬性文件,一個表示英文,一個表示漢語,一個屬性文件表示一個語言,就能實現應用的國際化了。
日志記錄器挺簡單的,沒有很多東西,最主要的就是一個Logger接口:
? ? ? ??
- public ? interface ?Logger?{??
- ???? public ? static ? final ? int ?FATAL?=?Integer.MIN_VALUE;??
- ???? public ? static ? final ? int ?ERROR?=? 1 ;??
- ???? public ? static ? final ? int ?WARNING?=? 2 ;??
- ???? public ? static ? final ? int ?INFORMATION?=? 3 ;??
- ???? public ? static ? final ? int ?DEBUG?=? 4 ;??
- ???? public ?Container?getContainer();??
- ???? public ? void ?setContainer(Container?container);??
- ???? public ?String?getInfo();??
- ???? public ? int ?getVerbosity();??
- ???? public ? void ?setVerbosity( int ?verbosity);??
- ???? public ? void ?addPropertyChangeListener(PropertyChangeListener?listener);??
- ???? public ? void ?log(String?message);??
- ???? public ? void ?log(Exception?exception,?String?msg);??
- ???? public ? void ?log(String?message,?Throwable?throwable);??
- ???? public ? void ?log(String?message,? int ?verbosity);??
- ???? public ? void ?log(String?message,?Throwable?throwable,? int ?verbosity);??
- ???? public ? void ?removePropertyChangeListener(PropertyChangeListener?listener);??
- }??
- public ? void ?start()? throws ?LifecycleException?{??
- ??
- ?????? //?Validate?and?update?our?current?component?state ??
- ?????? if ?(started)??
- ?????????? throw ? new ?LifecycleException??
- ??????????????(sm.getString( "fileLogger.alreadyStarted" ));??
- ??????lifecycle.fireLifecycleEvent(START_EVENT,? null ); //觸發生命周期事件 ??
- ??????started?=? true ;??
- ??
- ??}??
- private ? void ?open()?{??
- ??
- ??????? //?Create?the?directory?if?necessary ??
- ???????File?dir?=? new ?File(directory); //directory等于logs,即在文件夾logs下新建日志文件 ??
- ??????? if ?(!dir.isAbsolute())??
- ???????????dir?=? new ?File(System.getProperty( "catalina.base" ),?directory);??
- ???????dir.mkdirs();??
- ??
- ??????? //?Open?the?current?log?file ??
- ??????? try ?{??
- ???????????String?pathname?=?dir.getAbsolutePath()?+?File.separator?+??
- ???????????????prefix?+?date?+?suffix;??
- ???????????writer?=? new ?PrintWriter( new ?FileWriter(pathname,? true ),? true );??
- ???????}? catch ?(IOException?e)?{??
- ???????????writer?=? null ;??
- ???????}??
- ??
- ???}??
- public ? void ?log(String?msg)?{??
- ??
- ?????? //?Construct?the?timestamp?we?will?use,?if?requested ??
- ??????Timestamp?ts?=? new ?Timestamp(System.currentTimeMillis());??
- ??????String?tsString?=?ts.toString().substring( 0 ,? 19 );??
- ??????String?tsDate?=?tsString.substring( 0 ,? 10 );??
- ??
- ?????? //?If?the?date?has?changed,?switch?log?files ??
- ?????? if ?(!date.equals(tsDate))?{?? //如果日期改變,則新建一個日志文件。 ??
- ?????????? synchronized ?( this )?{??
- ?????????????? if ?(!date.equals(tsDate))?{??
- ??????????????????close();??
- ??????????????????date?=?tsDate;??
- ??????????????????open();??
- ??????????????}??
- ??????????}??
- ??????}??
- ??
- ?????? //?Log?this?message,?timestamped?if?necessary ??
- ?????? if ?(writer?!=? null )?{??
- ?????????? if ?(timestamp)?{??
- ??????????????writer.println(tsString?+? "?" ?+?msg); //寫入時間和日志信息進日志文件中。 ??
- ??????????}? else ?{??
- ??????????????writer.println(msg);??
- ??????????}??
- ??????}??
- ??
- ??}??
writer.println把時間和日志信息寫進日志文件中。當然,這個日志記錄器一般是給Tomcat自己用的,我們也可以實現Logger接口,然后重寫它的open方法(打開我們自己的日志文件)和log方法(用來在我們自己的日志文件中記錄日志信息)。
現在再來看剛才提到的代碼sm.getString("fileLogger.alreadyStarted")。在理解這句代碼前先看一個jdk的類ResourceBundle,這個類提供了國際化的方便。這個類的作用就是讀取.properties文件,但是會根據文件名來獲取當前系統的語言信息,然后讀取對應文件的屬性值。當然首先要有各國不同的屬性文件,才能國際化,Tomcat的每個包下都有幾個不同的屬性文件,org.apache.catalina.logger包下有如下三個屬性文件:
- LocalStrings_es.properties??
- LocalStrings_ja.properties??
- LocalStrings.properties??
- fileLogger.alreadyStarted=File?Logger?has?already?been?started??
- fileLogger.notStarted=File?Logger?has?not?yet?been?started??
- tomcatLogger.alreadyStarted=Tomcat?Logger?has?already?been?started??
- tomcatLogger.notStarted=Tomcat?Logger?has?not?yet?been?started??
ResourceBundle類通過getBundle方法獲取,參數是屬性文件的包名家名字前綴,上面就是包名加LocalStrings。通過getString(String key)方法獲取屬性文件中的參數:
現在來看代碼sm.getString("fileLogger.alreadyStarted"),sm是StringManager的實例,在FileLogger中已經初始化:
- private ?StringManager?sm?=StringManager.getManager(Constants.Package);??
Constants.Package得到包的名字,getManager方法代碼如下:
- public ? synchronized ? static ?StringManager?getManager(String?packageName)?{??
- ???????StringManager?mgr?=?(StringManager)managers.get(packageName);??
- ??????? if ?(mgr?==? null )?{??
- ???????????mgr?=? new ?StringManager(packageName); //新建一個StringManager ??
- ???????????managers.put(packageName,?mgr);??
- ???????}??
- ??????? return ?mgr;??
- ???}??
代碼很好理解,如果已經有StringManager實例了就直接從managers(這是一個Hashtable)中拿,沒有就新建一個。看StringManager的構造方法:
- private ?StringManager(String?packageName)?{??
- ???????String?bundleName?=?packageName?+? ".LocalStrings" ;??
- ???????bundle?=?ResourceBundle.getBundle(bundleName);??
- ???}??
- public ?String?getString(String?key)?{??
- ??????? if ?(key?==? null )?{??
- ???????????String?msg?=? "key?is?null" ;??
- ??
- ??????????? throw ? new ?NullPointerException(msg);??
- ???????}??
- ??
- ???????String?str?=? null ;??
- ??
- ??????? try ?{??
- ???????????str?=?bundle.getString(key);??
- ???????}? catch ?(MissingResourceException?mre)?{??
- ???????????str?=? "Cannot?find?message?associated?with?key?'" ?+?key?+? "'" ;??
- ???????}??
- ??
- ??????? return ?str;??
- ???}??
重點是budle.getString(key),這句代碼能拿到LocalStrings.properties文件的key屬性(這里是fileLogger.alreadyStarted)的值,即File Logger has already been started。這樣我們便能定義多個屬性文件,一個表示英文,一個表示漢語,一個屬性文件表示一個語言,就能實現應用的國際化了。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
