How Tomcat Works 15: Digester
一、概述 前面章節中,使用hard-code來管理各component間的從屬關係,如果需要改變則需要重新編譯Bootstrap類。幸運的是tomcat設計者採用了更優雅的方法來管理配置,即XML檔案server.xml. 這樣我們只需要修改server.xml檔案就可以設定tomcat。如:<context docBase='myApp' path="/myApp"/> Tomcat採用了開源包Digester來完成xml元素到java物件的轉換。而WebApp的配置則不同,它在app內部WEB-INF下的xml檔案
二、組成 1. Rule規則 用特定的pattern解析xml內容,生成對應的物件和路徑
void begin(org.xml.sax.Attribute)
void end()
void addRule(String pattern, Rule rule)
2. 案例
<employee firstName="Brant" lastName="Kobe"> <office> <address streetName="Los Angle" streetNumber="10" /> </office> </employee>
3. 建立物件addObjectCreate(…),四種過載方法
void addObjectCreate(String pattern, Class clazz); void addObjectCreate(String pattern, String className); void addObjectCreate(String pattern, String attributeName); void addObjectCreate(String pattern, Class clazz, String attributeName); // digester.addObjectCreate("employee", "com.cisco.tomcat.Employee", "streetNumber")
4. 設定屬性void addSetProperties(String pattern)
void addProperties(String pattern)// addSetproperties("employee")-->will call setFirstName() and setLastName()
5. 設定屬性
void addSetNext("employee/office", "addOffice");// 會呼叫employee.addOffice()方法
解析時,會按照樹形結構依次將employee和office入棧, 然後呼叫addSetNext()構建元素關係
三、ContextConfig介紹 1. 作用 ContextConfig對於standardContext有很重要的作用,比如它關聯了authenticator valve, CertificateValve等,更重要的ContextConfig例項也要讀取解析預設web.xml檔案和webApp下的web.xml檔案,並轉換xml元素成java物件 2. Web.xml的配置 CATALINA_HOME下的預設web.xml檔案定義了預設Servlets的map,MIME型別的拓展名map,定義了預設session超時時間,定義歡迎檔案列表 3. WebApp下的web.xml配置 web.xml是應用配置檔案,放在webapp的WEB-INF下面。不過他們兩都不是必需檔案 4. Contextconfig功能: 為每個servlet元素建立一個StandardWrapper,所以後續配置更方便無需手工例項化Wrapper 5. 案例 在bootStrap類中,可以直接code:
lifecyclelistener listener = new ContextConfig();
((Lifecycle)context).addLifecycleListener(lisenter);
在context的啟動和關閉時會fire event, START_EVENT和STOP_EVENT。這時就會觸發ContextConfig的lifecycleEvent(lifecycleEvent event),lifecycleEvent方法如下:
@Override
public void LifecycleEvent(com.cisco.tomcat.lifecycle.LifecycleEvent lifecycleEvent) {
if(lifecycleEvent.getType().equals(Lifecycle.START_EVENT)) {
start();
}else {
stop();
}
}
Start方法如下:
private void start() {
ok = true;
// 初始化,設定Engine.defaultContext, Host.defaultContext
context.setConfigured(false);
Container container = context.getParent();
if (container instanceof Host) {
((Host) container).importDefaultContext(context);
container = container.getParent;
}
if (container instanceof Engine) {
((Engine) container).importDefaultContext(context);
}
// 處理預設的web.xml和WebApp的web.xml檔案
defaultConfig();
applicationConfig();
if (ok) {
validateSecurityRoles();
}
// 為新增的listener類掃描標籤庫描述符
if (ok) {
tldScan();
}
// 若需要,則配置證書暴露valve
if (ok) {
certificatesConfig();
}
// 若需要,則配置認證
if (ok) {
authenticatorConfig();
}
// 若請求後,dump下context內部的pipeline的內容
Pipeline pipeline = context.getPipeline();
Valve[] valves = pipeline.getValves();
for (int i = 0; i < valves.length; i++) {
log(" " + valves.getInfo());
}
// 若無其他問題引入,設定我們的App為Available狀態
if (ok) {
context.setConfigured(true);
} else {
log(sm.getString("contextConfig.unavailable"));
context.setConfigured(false);
}
}
defaultConfig 方法:解析%CATALINA_HOME%/conf資料夾中的web.xml
private void defaultConfig() {
// 開啟預設web.xml檔案
File file = new File(Constants.DefaultWebXml);
FileInputStream stream = new FileInputStream(file.getCanonicalPath());
stream.close();
InputSource is = new InputSource("file://"+file.getAbsolutePath());
stream = new FileInputStream(file);
is.setByteStream(stream);
webDigester.clear();
webDigester.push(context);
webDigetster.parse(is);
}
applicationConfig方法:解析APP下的WEB-INF/下的web.xml
private void applicationConfig() {
ServletContext servletContext = context.getServletContext();
InputStream stream = servletContext.getResourceAsStream(Constants.ApplicationWebXml);
URL url = servletContext.getResource(Constants.ApplicationWebXml);
InputSource is = new InputSrouce(url.toExternalForm());
is.setByteStream(stream);
webDigester.clear();
webDigester.push(context);
webDigester.parse(is);
}
靜態建立WebDigester的方法
private static Digester createWebDigester() {
Digester webDigester = new Digester();
webDigester.setValidating(true);
URL url = ContextConfig.class.getResource(Constants.WebDtdResourcePath_22);
webDigester.register(Constants.WebDtdPublicId_22, url.toString());
url = ContextConfig.class.getResource(Constants.WneDtdResourcePath_23);
webDigester.register(Constants.WebDtdPublicId_23, url.toString());
webDigester.addRuleSet(new WebRuleSet());
return webDigester;
}