zoukankan      html  css  js  c++  java
  • 深入刨析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,站点的配置文件看起

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

    appBase="webapps"

    name="localhost"

    children=context的HashMap

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

    代码中能看到的设置

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

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

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

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

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

    webDigester.push(context);

    将context对象压入digester的内部栈,然后使用规则去解析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"));

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

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

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

    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>

    这就是调用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的过程

    结束:

  • 相关阅读:
    Oracle配置监听
    Oracle创建表空间和分配用户权限
    Dijkstra
    【刷题】【dp】【记忆化搜索】单词游戏
    【刷题】【记忆化搜索】【dp】Longtail Hedgehog
    【刷题】【dp】 Make The Fence Great Again
    【技巧】【卡常】
    【二分】【基础】(跳石头)(合并果子)(蚯蚓)
    【笔记】两种交换元素的方案对比
    【刷题】【单调栈】请客
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/15011262.html
Copyright © 2011-2022 走看看