深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

writedby 张艳涛

记得当年是学习jsp的时候,写过web.xml中的标签.在之后的springmvc中也是有关于配置mvc 过滤器 和dispatchServlet的标签,之前是看不懂呢!看到这本how tomcat works之后,现在比较清楚了,

那么就写下自己的理解

在webapps/app1/目录下的web.xml文件

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app>
<servlet>
<servlet-name>Modern</servlet-name>
<servlet-class>ModernServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>Primitive</servlet-name>
<servlet-class>PrimitiveServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Modern</servlet-name>
<url-pattern>/Modern</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Primitive</servlet-name>
<url-pattern>/Primitive</url-pattern>
</servlet-mapping>
</web-app>

这可是标准的web.xml文件,他的作用,用代码表示出来为

 Wrapper wrapper1 = new StandardWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new StandardWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet"); Context context = new StandardContext();
// StandardContext's start method adds a default mapper
context.setPath("/app1");
context.setDocBase("app1"); context.addChild(wrapper1);
context.addChild(wrapper2); LifecycleListener listener = new SimpleContextConfig();
((Lifecycle) context).addLifecycleListener(listener); Host host = new StandardHost();
host.addChild(context);
host.setName("localhost");
host.setAppBase("webapps"); Loader loader = new WebappLoader();
context.setLoader(loader);
// context.addServletMapping(pattern, name);
context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");

描述一下,上述行为,上述为tomcat实现的应编码,StandardContext 是一个可以代表一个web应用,这里是我们的app1应用, 对应的标签就是<web-app> ,

StandardWrapper是代表一个Servlet程序,这里就是是我们wrapper1,对应的标签就是<servlet>其中的行为

    wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
对应了

  <servlet-name>Primitive</servlet-name>
  <servlet-class>PrimitiveServlet</servlet-class>

接着就是配置映射关系

  context.addServletMapping("/Primitive", "Primitive");
  context.addServletMapping("/Modern", "Modern");

对应的标签为

  <servlet-mapping>
  <servlet-name>Modern</servlet-name>
  <url-pattern>/Modern</url-pattern>
  </servlet-mapping>

你说的看似是这么回事,那么到底tomcat是如何解析的呢?那么我们看源码说话

HostConfig,站点的配置文件看起

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

先解释一下这个host对象,这个是tomcat的4大容器之一,engine,host,context,wrapper; host代表的是一个站点,比如host的重要的属性有

appBase="webapps"

name="localhost"

children=context的HashMap

那么能看的到,deloyApps代码中是分析webapps目录下的文件,对于每个文件都要新建一个StandardContext对象

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

代码中能看到的设置

context.setPath(contextPath);
context.setDocBase(docBase);

和自己手写BootStrap文件行为是一致(bootStrap参见源码第15章),那么还是没有看到如何解析web.xml呢

解析web.xml在ContextConfig文件中,在start()方法中有

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

其中1是解析conf/web.xml文件的, 其2是解析web应用下的web.xml文件的

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

能看到使用一个Digester 去读取 jndi:/localhost/app1/WEB-INF/web.xml这个文件,新建一个Digester,重要的代码有

webDigester.push(context);

将context对象压入digester的内部栈,然后使用规则去解析web.xml文件,那么重要的是看解析规则,解析规则,在新建这个对象的时候添加的

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

看这个类中的方法

    public void addRuleInstances(Digester digester) {

        digester.addRule(prefix + "web-app",
new SetPublicIdRule(digester, "setPublicId")); digester.addCallMethod(prefix + "web-app/context-param",
"addParameter", 2);
digester.addCallParam(prefix + "web-app/context-param/param-name", 0);
digester.addCallParam(prefix + "web-app/context-param/param-value", 1); digester.addCallMethod(prefix + "web-app/display-name",
"setDisplayName", 0); digester.addRule(prefix + "web-app/distributable",
new SetDistributableRule(digester)); digester.addObjectCreate(prefix + "web-app/ejb-local-ref",
"org.apache.catalina.deploy.ContextLocalEjb");
digester.addSetNext(prefix + "web-app/ejb-local-ref",
"addLocalEjb",
"org.apache.catalina.deploy.ContextLocalEjb"); digester.addCallMethod(prefix + "web-app/ejb-local-ref/description",
"setDescription", 0);
digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link",
"setLink", 0);
digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name",
"setName", 0);
digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type",
"setType", 0);
digester.addCallMethod(prefix + "web-app/ejb-local-ref/local",
"setLocal", 0);
digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home",
"setHome", 0); digester.addObjectCreate(prefix + "web-app/ejb-ref",
"org.apache.catalina.deploy.ContextEjb");
digester.addSetNext(prefix + "web-app/ejb-ref",
"addEjb",
"org.apache.catalina.deploy.ContextEjb"); digester.addCallMethod(prefix + "web-app/ejb-ref/description",
"setDescription", 0);
digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link",
"setLink", 0);
digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name",
"setName", 0);
digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type",
"setType", 0);
digester.addCallMethod(prefix + "web-app/ejb-ref/home",
"setHome", 0);
digester.addCallMethod(prefix + "web-app/ejb-ref/remote",
"setRemote", 0); digester.addObjectCreate(prefix + "web-app/env-entry",
"org.apache.catalina.deploy.ContextEnvironment");
digester.addSetNext(prefix + "web-app/env-entry",
"addEnvironment",
"org.apache.catalina.deploy.ContextEnvironment"); digester.addCallMethod(prefix + "web-app/env-entry/description",
"setDescription", 0);
digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name",
"setName", 0);
digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type",
"setType", 0);
digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value",
"setValue", 0); digester.addObjectCreate(prefix + "web-app/error-page",
"org.apache.catalina.deploy.ErrorPage");
digester.addSetNext(prefix + "web-app/error-page",
"addErrorPage",
"org.apache.catalina.deploy.ErrorPage"); digester.addCallMethod(prefix + "web-app/error-page/error-code",
"setErrorCode", 0);
digester.addCallMethod(prefix + "web-app/error-page/exception-type",
"setExceptionType", 0);
digester.addCallMethod(prefix + "web-app/error-page/location",
"setLocation", 0); digester.addObjectCreate(prefix + "web-app/filter",
"org.apache.catalina.deploy.FilterDef");
digester.addSetNext(prefix + "web-app/filter",
"addFilterDef",
"org.apache.catalina.deploy.FilterDef"); digester.addCallMethod(prefix + "web-app/filter/description",
"setDescription", 0);
digester.addCallMethod(prefix + "web-app/filter/display-name",
"setDisplayName", 0);
digester.addCallMethod(prefix + "web-app/filter/filter-class",
"setFilterClass", 0);
digester.addCallMethod(prefix + "web-app/filter/filter-name",
"setFilterName", 0);
digester.addCallMethod(prefix + "web-app/filter/large-icon",
"setLargeIcon", 0);
digester.addCallMethod(prefix + "web-app/filter/small-icon",
"setSmallIcon", 0); digester.addCallMethod(prefix + "web-app/filter/init-param",
"addInitParameter", 2);
digester.addCallParam(prefix + "web-app/filter/init-param/param-name",
0);
digester.addCallParam(prefix + "web-app/filter/init-param/param-value",
1); digester.addObjectCreate(prefix + "web-app/filter-mapping",
"org.apache.catalina.deploy.FilterMap");
digester.addSetNext(prefix + "web-app/filter-mapping",
"addFilterMap",
"org.apache.catalina.deploy.FilterMap"); digester.addCallMethod(prefix + "web-app/filter-mapping/filter-name",
"setFilterName", 0);
digester.addCallMethod(prefix + "web-app/filter-mapping/servlet-name",
"setServletName", 0);
digester.addCallMethod(prefix + "web-app/filter-mapping/url-pattern",
"setURLPattern", 0); digester.addCallMethod(prefix + "web-app/listener/listener-class",
"addApplicationListener", 0); digester.addObjectCreate(prefix + "web-app/login-config",
"org.apache.catalina.deploy.LoginConfig");
digester.addSetNext(prefix + "web-app/login-config",
"setLoginConfig",
"org.apache.catalina.deploy.LoginConfig"); digester.addCallMethod(prefix + "web-app/login-config/auth-method",
"setAuthMethod", 0);
digester.addCallMethod(prefix + "web-app/login-config/realm-name",
"setRealmName", 0);
digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-error-page",
"setErrorPage", 0);
digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-login-page",
"setLoginPage", 0); digester.addCallMethod(prefix + "web-app/mime-mapping",
"addMimeMapping", 2);
digester.addCallParam(prefix + "web-app/mime-mapping/extension", 0);
digester.addCallParam(prefix + "web-app/mime-mapping/mime-type", 1); digester.addCallMethod(prefix + "web-app/resource-env-ref",
"addResourceEnvRef", 2);
digester.addCallParam(prefix + "web-app/resource-env-ref/resource-env-ref-name", 0);
digester.addCallParam(prefix + "web-app/resource-env-ref/resource-env-ref-type", 1); digester.addObjectCreate(prefix + "web-app/resource-ref",
"org.apache.catalina.deploy.ContextResource");
digester.addSetNext(prefix + "web-app/resource-ref",
"addResource",
"org.apache.catalina.deploy.ContextResource"); digester.addCallMethod(prefix + "web-app/resource-ref/description",
"setDescription", 0);
digester.addCallMethod(prefix + "web-app/resource-ref/res-auth",
"setAuth", 0);
digester.addCallMethod(prefix + "web-app/resource-ref/res-ref-name",
"setName", 0);
digester.addCallMethod(prefix + "web-app/resource-ref/res-sharing-scope",
"setScope", 0);
digester.addCallMethod(prefix + "web-app/resource-ref/res-type",
"setType", 0); digester.addObjectCreate(prefix + "web-app/security-constraint",
"org.apache.catalina.deploy.SecurityConstraint");
digester.addSetNext(prefix + "web-app/security-constraint",
"addConstraint",
"org.apache.catalina.deploy.SecurityConstraint"); digester.addRule(prefix + "web-app/security-constraint/auth-constraint",
new SetAuthConstraintRule(digester));
digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name",
"addAuthRole", 0);
digester.addCallMethod(prefix + "web-app/security-constraint/display-name",
"setDisplayName", 0);
digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee",
"setUserConstraint", 0); digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection",
"org.apache.catalina.deploy.SecurityCollection");
digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection",
"addCollection",
"org.apache.catalina.deploy.SecurityCollection");
digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method",
"addMethod", 0);
digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern",
"addPattern", 0);
digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name",
"setName", 0); digester.addCallMethod(prefix + "web-app/security-role/role-name",
"addSecurityRole", 0); digester.addRule(prefix + "web-app/servlet",
new WrapperCreateRule(digester));
digester.addSetNext(prefix + "web-app/servlet",
"addChild",
"org.apache.catalina.Container"); digester.addCallMethod(prefix + "web-app/servlet/init-param",
"addInitParameter", 2);
digester.addCallParam(prefix + "web-app/servlet/init-param/param-name",
0);
digester.addCallParam(prefix + "web-app/servlet/init-param/param-value",
1); digester.addCallMethod(prefix + "web-app/servlet/jsp-file",
"setJspFile", 0);
digester.addCallMethod(prefix + "web-app/servlet/load-on-startup",
"setLoadOnStartupString", 0);
digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name",
"setRunAs", 0); digester.addCallMethod(prefix + "web-app/servlet/security-role-ref",
"addSecurityReference", 2);
digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1);
digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0); digester.addCallMethod(prefix + "web-app/servlet/servlet-class",
"setServletClass", 0);
digester.addCallMethod(prefix + "web-app/servlet/servlet-name",
"setName", 0); digester.addCallMethod(prefix + "web-app/servlet-mapping",
"addServletMapping", 2);
digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1);
digester.addCallParam(prefix + "web-app/servlet-mapping/url-pattern", 0); digester.addCallMethod(prefix + "web-app/session-config/session-timeout",
"setSessionTimeout", 1,
new Class[] { Integer.TYPE });
digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0); digester.addCallMethod(prefix + "web-app/taglib",
"addTaglib", 2);
digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1);
digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0); digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file",
"addWelcomeFile", 0); }

对于规则分析如下

        digester.addRule(prefix + "web-app",
new SetPublicIdRule(digester, "setPublicId"));

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

没做别的就是调用了context的 setPublicId方法

对于没设计的规则不解读,那么找 <servlet> 标签

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

那么遇到web-app/servlet的第一规则是WrapperCreateRule

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

begin中执行了,peek出栈中的context对象(就是之前push进去的代表app1的standardContext对象,

那么新建一个wrapper对象,将wrapper对象 push的digest栈中,

接下的规则是

 digester.addSetNext(prefix + "web-app/servlet",
"addChild",
"org.apache.catalina.Container");

调用栈顶-1位置的对象的 addChild() 方法将栈顶对象作为参数,添加的context对象(栈顶-1位置对象)

接着遇到的标签是<servlet-name>Modern</servlet-name>

深入刨析tomcat 之---第11篇 how tomcat works( 第15章 ) 如何解析web.xml 文件

这就是调用wrapper对象的setname方法将参数 "Modern" 标签的值,放入的wrapper对象中

不就是调用了

Wrapper wrapper2 = new StandardWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");

如下的语句吗?

确实是,到此就分析完毕了,

总结: 以上涉及了俩个问题1, tomcat是如何给host对象配置web.xml规则的StandardContext的,就是看webapps文件下有几个web应用,给每个新建一个StandardContext

在新建一个digester将context压栈,接着按规则解析web.xml.解析过程无非就是三种,一个新建对象,2调用对象方法,3 建立栈顶元素和栈顶-1位置元素的关系(addChild方法)

第二个问题是:digester解析web.xml的过程

结束:

上一篇:cocos2dx 3.8版关于#include "GB2ShapeCache-x.h"


下一篇:python3 module中__init__.py的需要注意的地方