Digester
在引导类中我们需要创建连接器、context、wrapper及其它组件,同时还需要通过调用set方法对相互之间进行关联,同时还需要为这些对象设置属性,这些都进行硬编码,那么一旦需要做任何改动都需要重新编译Bootstray类,Tomcat使用Digester来解决这个问题,把配置信息都放在xml文件当中,像server.xml、web.xml等,通过Digester把xml文件解析成java对象,xml中的元素属性被设置为解析对象的属性。
Digester
Digester是Jakarta Commons项目下的一个开源子项目,commons-digester.jar组件主要有三个包:
1、 org.apache.commons.digester提供对基于规则的任意xml文档进行处理;
2、 org.apache.commons.digester.rss提供了一些使用Digester解析XML文档的示例;
3、 org.apache.commons.digester.xmlruls提供了一些用XML定义规则。
Digester类
org.apache.commons.digester.Digester类Digester库中的主要类,用它来解析xml文档,对于每个xml文档中的元素Digester都会去检查是否需要做一些动作,通过它可以:
1、 创建对象;
2、 设置属性;
3、 调用方法;
4、 创建对象关系;
5、 验证XML文档。
Digester操作都是通过Rule来实现的。
Rule类
当Digester实例遇到一个XML元素开始的时候,它就会调用匹配Rule的begin方法,当Digester实例遇到一个XML元素结束的时候,它就会调用匹配Rule模式的end方法。这些Rule是在Digester创建对象、调用方法、创建对象关系的时候通过调用addRule方法添加的。
ContextConfig
在Catalina的容器中,与其他容器不同的是StandardContext容器必须要有一个监听器,监听器会配置StandardContext实例,并把configred属性置为true,在Tomcat中这个监听器就是ContextConfig,它会给StandardContext分配认证器value、认证value给StandardContext的管道。
同时ContextConfig实例会去解析Tomcat默认web.xml和应用部署web.xml,并跟进其中的配置生成相应的Java对象。默认web.xml中定义了在CATALINA_HOME路径下的conf目录中,它定义了一些默认的servlet及其映射,映射文件MIME类型,欢迎文件列表等,应用文件放在WEB-INF目录下,ContextConfig会为每一个servlet创建一个StandardWrapper,在启动时只需要把ContextConfig加入到StandardContext的监听器中即可:
LifecycleListener listener = new ContextConfig();
((Lifecycle) context).addLifecycleListener(listener);
ContextConfig会处理StandardContext的START_EVENT和STOP_EVENT事件:
public void lifecycleEvent(LifecycleEvent event) {
// Identify the context we are associated with
try {
context = (Context) event.getLifecycle();
if (context instanceof StandardContext) {
int contextDebug = ((StandardContext) context).getDebug();
if (contextDebug > this.debug)
this.debug = contextDebug;
}
} catch (ClassCastException e) {
log(sm.getString("contextConfig.cce", event.getLifecycle()), e);
return;
}
// Process the event that has occurred
if (event.getType().equals(Lifecycle.START_EVENT))
start();
else if (event.getType().equals(Lifecycle.STOP_EVENT))
stop();
}
根据事件它会去调用start和stop方法。
start实现如下:
private synchronized void start() {
if (debug > 0)
log(sm.getString("contextConfig.start"));
context.setConfigured(false);
ok = true;
// Set properties based on DefaultContext
Container container = context.getParent();
if( !context.getOverride() ) {
if( container instanceof Host ) {
((Host)container).importDefaultContext(context);
container = container.getParent();
}
if( container instanceof Engine ) {
((Engine)container).importDefaultContext(context);
}
}
// Process the default and application web.xml files
defaultConfig();
applicationConfig();
if (ok) {
validateSecurityRoles();
}
// Scan tag library descriptor files for additional listener classes
if (ok) {
try {
tldScan();
} catch (Exception e) {
log(e.getMessage(), e);
ok = false;
}
}
// Configure a certificates exposer valve, if required
if (ok)
certificatesConfig();
// Configure an authenticator if we need one
if (ok)
authenticatorConfig();
// Dump the contents of this pipeline if requested
if ((debug >= 1) && (context instanceof ContainerBase)) {
log("Pipline Configuration:");
Pipeline pipeline = ((ContainerBase) context).getPipeline();
Valve valves[] = null;
if (pipeline != null)
valves = pipeline.getValves();
if (valves != null) {
for (int i = 0; i < valves.length; i++) {
log(" " + valves[i].getInfo());
}
}
log("======================");
}
// Make our application available if no problems were encountered
if (ok)
context.setConfigured(true);
else {
log(sm.getString("contextConfig.unavailable"));
context.setConfigured(false);
}
}
start方法中回去调用defaultConfig和applicationConfig方法,分别去解析默认web.xml和应用web.xml。
defaultConfig
private void defaultConfig() {
// Open the default web.xml file, if it exists
File file = new File(Constants.DefaultWebXml);
if (!file.isAbsolute())
file = new File(System.getProperty("catalina.base"),
Constants.DefaultWebXml);
FileInputStream stream = null;
try {
stream = new FileInputStream(file.getCanonicalPath());
stream.close();
stream = null;
} catch (FileNotFoundException e) {
log(sm.getString("contextConfig.defaultMissing"));
return;
} catch (IOException e) {
log(sm.getString("contextConfig.defaultMissing"), e);
return;
}
// Process the default web.xml file
synchronized (webDigester) {
try {
InputSource is =
new InputSource("file://" + file.getAbsolutePath());
stream = new FileInputStream(file);
is.setByteStream(stream);
webDigester.setDebug(getDebug());
if (context instanceof StandardContext)
((StandardContext) context).setReplaceWelcomeFiles(true);
webDigester.clear();
webDigester.push(context);
webDigester.parse(is);
} catch (SAXParseException e) {
log(sm.getString("contextConfig.defaultParse"), e);
log(sm.getString("contextConfig.defaultPosition",
"" + e.getLineNumber(),
"" + e.getColumnNumber()));
ok = false;
} catch (Exception e) {
log(sm.getString("contextConfig.defaultParse"), e);
ok = false;
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
log(sm.getString("contextConfig.defaultClose"), e);
}
}
}
}
applicationConfig
private void applicationConfig() {
// Open the application web.xml file, if it exists
InputStream stream = null;
ServletContext servletContext = context.getServletContext();
if (servletContext != null)
stream = servletContext.getResourceAsStream
(Constants.ApplicationWebXml);
if (stream == null) {
log(sm.getString("contextConfig.applicationMissing"));
return;
}
// Process the application web.xml file
synchronized (webDigester) {
try {
URL url =
servletContext.getResource(Constants.ApplicationWebXml);
InputSource is = new InputSource(url.toExternalForm());
is.setByteStream(stream);
webDigester.setDebug(getDebug());
if (context instanceof StandardContext) {
((StandardContext) context).setReplaceWelcomeFiles(true);
}
webDigester.clear();
webDigester.push(context);
webDigester.parse(is);
} catch (SAXParseException e) {
log(sm.getString("contextConfig.applicationParse"), e);
log(sm.getString("contextConfig.applicationPosition",
"" + e.getLineNumber(),
"" + e.getColumnNumber()));
ok = false;
} catch (Exception e) {
log(sm.getString("contextConfig.applicationParse"), e);
ok = false;
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
log(sm.getString("contextConfig.applicationClose"), e);
}
}
}
}
创建web Digester
defaultConfig和applicationConfig都会创建一个Digester:
private static Digester createWebDigester() {
URL url = null;
Digester webDigester = new Digester();
webDigester.setValidating(true);
url = ContextConfig.class.getResource(Constants.WebDtdResourcePath_22);
webDigester.register(Constants.WebDtdPublicId_22,
url.toString());
url = ContextConfig.class.getResource(Constants.WebDtdResourcePath_23);
webDigester.register(Constants.WebDtdPublicId_23,
url.toString());
webDigester.addRuleSet(new WebRuleSet());
return (webDigester);
}