Tomcat源碼分析(六)--日志記錄器和國(guó)際化
系統(tǒng)
2019-08-12 01:32:18
2126 0
本系列轉(zhuǎn)載自?http://blog.csdn.net/haitao111313/article/category/1179996?
?
日志記錄器挺簡(jiǎn)單的,沒(méi)有很多東西,最主要的就是一個(gè)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);??
}??
只要實(shí)現(xiàn)Logger就能有一個(gè)自己的日志記錄器,其中setContainer是把日志記錄器跟具體的容器關(guān)聯(lián),setVerbosity是設(shè)置日志的級(jí)別,log是具體的日志記錄函數(shù)。FATAL,ERROR,WARNING,INFORMATION,DEBUG代表日志記錄的五個(gè)級(jí)別,看單詞就能明白意思。這里主要講解一下FileLogger類(lèi),這是Tomcat的其中一個(gè)日志記錄器,它把日志記錄在一個(gè)文件中,F(xiàn)ileLogger的啟動(dòng)方法和關(guān)閉僅僅是出發(fā)一個(gè)生命周期事件,并不做其他的事情:
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
);
//觸發(fā)生命周期事件
??
??????started?=?
true
;??
??
??}??
這里有一行代碼sm.getString("fileLogger.alreadyStarted"),牽涉到國(guó)際化的問(wèn)題,等下再說(shuō)這個(gè)問(wèn)題。現(xiàn)在先看日志記錄器,F(xiàn)ileLogger的open方法打開(kāi)一個(gè)文件用來(lái)記錄日志:
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
;??
???????}??
??
???}??
這里得到一個(gè)PrintWriter的輸出流writer,在log方法記錄日志的時(shí)候會(huì)用到,下面看log方法:
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))?{??
//如果日期改變,則新建一個(gè)日志文件。
??
??????????
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);
//寫(xiě)入時(shí)間和日志信息進(jìn)日志文件中。
??
??????????}?
else
?{??
??????????????writer.println(msg);??
??????????}??
??????}??
??
??}??
writer.println把時(shí)間和日志信息寫(xiě)進(jìn)日志文件中。當(dāng)然,這個(gè)日志記錄器一般是給Tomcat自己用的,我們也可以實(shí)現(xiàn)Logger接口,然后重寫(xiě)它的open方法(打開(kāi)我們自己的日志文件)和log方法(用來(lái)在我們自己的日志文件中記錄日志信息)。
現(xiàn)在再來(lái)看剛才提到的代碼sm.getString("fileLogger.alreadyStarted")。在理解這句代碼前先看一個(gè)jdk的類(lèi)ResourceBundle,這個(gè)類(lèi)提供了國(guó)際化的方便。這個(gè)類(lèi)的作用就是讀取.properties文件,但是會(huì)根據(jù)文件名來(lái)獲取當(dāng)前系統(tǒng)的語(yǔ)言信息,然后讀取對(duì)應(yīng)文件的屬性值。當(dāng)然首先要有各國(guó)不同的屬性文件,才能?chē)?guó)際化,Tomcat的每個(gè)包下都有幾個(gè)不同的屬性文件,org.apache.catalina.logger包下有如下三個(gè)屬性文件:
LocalStrings_es.properties??
LocalStrings_ja.properties??
LocalStrings.properties??
分別表示三種語(yǔ)言的屬性文件。LocalStrings.properties屬性文件是默認(rèn)的屬性文件。看LocalStrings.properties屬性中的內(nèi)容:
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類(lèi)通過(guò)getBundle方法獲取,參數(shù)是屬性文件的包名家名字前綴,上面就是包名加LocalStrings。通過(guò)getString(String key)方法獲取屬性文件中的參數(shù):
現(xiàn)在來(lái)看代碼sm.getString("fileLogger.alreadyStarted"),sm是StringManager的實(shí)例,在FileLogger中已經(jīng)初始化:
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);
//新建一個(gè)StringManager
??
???????????managers.put(packageName,?mgr);??
???????}??
???????
return
?mgr;??
???}??
代碼很好理解,如果已經(jīng)有StringManager實(shí)例了就直接從managers(這是一個(gè)Hashtable)中拿,沒(méi)有就新建一個(gè)。看StringManager的構(gòu)造方法:
private
?StringManager(String?packageName)?{??
???????String?bundleName?=?packageName?+?
".LocalStrings"
;??
???????bundle?=?ResourceBundle.getBundle(bundleName);??
???}??
看到我們熟悉的ResourceBundle類(lèi)了,根據(jù)上面的講解,ResourceBundle.getBundle(bundleName)能拿到默認(rèn)的屬性文件,也就是上面的LocalStrings.properties文件。再回到sm.getString("fileLogger.alreadyStarted"),看sm的getString方法:
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;??
???}??
重點(diǎn)是budle.getString(key),這句代碼能拿到LocalStrings.properties文件的key屬性(這里是fileLogger.alreadyStarted)的值,即File Logger has already been started。這樣我們便能定義多個(gè)屬性文件,一個(gè)表示英文,一個(gè)表示漢語(yǔ),一個(gè)屬性文件表示一個(gè)語(yǔ)言,就能實(shí)現(xiàn)應(yīng)用的國(guó)際化了。
Tomcat源碼分析(六)--日志記錄器和國(guó)際化
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】 元
喜歡作者