tomcat阅读第十三篇(tomcat ContextConfig(configureStart[Webconfig]))

这篇单独分析configureStart –>webconfig方法,下面是configureStart的代码

protected synchronized void configureStart() {
        // Called from StandardContext.start()

        if (log.isDebugEnabled()) {
            log.debug(sm.getString("contextConfig.start"));
        }

        if (log.isDebugEnabled()) {
            log.debug(sm.getString("contextConfig.xmlSettings",
                    context.getName(),
                    Boolean.valueOf(context.getXmlValidation()),
                    Boolean.valueOf(context.getXmlNamespaceAware())));
        }

        webConfig();

        if (!context.getIgnoreAnnotations()) {
            applicationAnnotationsConfig();
        }
        if (ok) {
            validateSecurityRoles();
        }

        // Configure an authenticator if we need one
        if (ok) {
            authenticatorConfig();
        }

       ………………………….
}

 WebConfig方法:

protected void webConfig() {
//创建WebXmlParser解析web.xml配置文件,实例化WebXml类 start
//goto 解析WebXmlParser
        WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
                context.getXmlValidation(), context.getXmlBlockExternal());
//goto分析解析WebXmlFragment
        Set<WebXml> defaults = new HashSet<>();
        defaults.add(getDefaultWebXmlFragment(webXmlParser));
//goto分析解析ContextWebXml
        WebXml webXml = createWebXml();
        InputSource contextWebXml = getContextWebXmlSource();
        if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
            ok = false;
        }
//创建WebXmlParser解析web.xml配置文件,实例化WebXml类 End
        ServletContext sContext = context.getServletContext();
        // Ordering is important here
        // Step 1. Identify all the JARs packaged with the application and those
        // provided by the container. If any of the application JARs have a
        // web-fragment.xml it will be parsed at this point. web-fragment.xml
        // files are ignored for container provided JARs.
//goto分析step1
        Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);
        // Step 2. Order the fragments.
//goto分析step2
        Set<WebXml> orderedFragments = null;
        orderedFragments =
                WebXml.orderWebFragments(webXml, fragments, sContext);

        // Step 3. Look for ServletContainerInitializer implementations

//goto分析step3
        if (ok) {
            processServletContainerInitializers();
        }

        if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
            // Step 4. Process /WEB-INF/classes for annotations and
            // @HandlesTypes matches
//goto分析step4
            Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();
            if (ok) {
                WebResource[] webResources =
                        context.getResources().listResources("/WEB-INF/classes");

                for (WebResource webResource : webResources) {
                    // Skip the META-INF directory from any JARs that have been
                    // expanded in to WEB-INF/classes (sometimes IDEs do this).
                    if ("META-INF".equals(webResource.getName())) {
                        continue;
                    }
                    processAnnotationsWebResource(webResource, webXml,
                            webXml.isMetadataComplete(), javaClassCache);
                }
            }

            // Step 5. Process JARs for annotations and
            // @HandlesTypes matches - only need to process those fragments we
            // are going to use (remember orderedFragments includes any
            // container fragments)
            if (ok) {
                processAnnotations(
                        orderedFragments, webXml.isMetadataComplete(), javaClassCache);
            }

            // Cache, if used, is no longer required so clear it
            javaClassCache.clear();
        }

        if (!webXml.isMetadataComplete()) {
//goto 分析step6~9
            // Step 6. Merge web-fragment.xml files into the main web.xml
            // file.
            if (ok) {
                ok = webXml.merge(orderedFragments);
            }

            // Step 7. Apply global defaults
            // Have to merge defaults before JSP conversion since defaults
            // provide JSP servlet definition.
            webXml.merge(defaults);

            // Step 8. Convert explicitly mentioned jsps to servlets
            if (ok) {
                convertJsps(webXml);
            }

            // Step 9. Apply merged web.xml to Context
            if (ok) {
                configureContext(webXml);
            }
        } else {
            webXml.merge(defaults);
            convertJsps(webXml);
            configureContext(webXml);
        }

        if (context.getLogEffectiveWebXml()) {
            log.info("web.xml:\n" + webXml.toXml());
        }

        // Always need to look for static resources
        // Step 10. Look for static resources packaged in JARs
//goto分析step10
        if (ok) {
            // Spec does not define an order.
            // Use ordered JARs followed by remaining JARs
            Set<WebXml> resourceJars = new LinkedHashSet<>();
            for (WebXml fragment : orderedFragments) {
                resourceJars.add(fragment);
            }
            for (WebXml fragment : fragments.values()) {
                if (!resourceJars.contains(fragment)) {
                    resourceJars.add(fragment);
                }
            }
            processResourceJARs(resourceJars);
            // See also StandardContext.resourcesStart() for
            // WEB-INF/classes/META-INF/resources configuration
        }
        // Step 11. Apply the ServletContainerInitializer config to the
        // context
//goto分析step11
        if (ok) {
            for (Map.Entry<ServletContainerInitializer,
                    Set<Class<?>>> entry :
                        initializerClassMap.entrySet()) {
                if (entry.getValue().isEmpty()) {
                    context.addServletContainerInitializer(
                            entry.getKey(), null);
                } else {
                    context.addServletContainerInitializer(
                            entry.getKey(), entry.getValue());
                }
            }
        }
}

1. 解析WebXmlParser:WebXmlParser解析填充webxml对象分析,先看WebXmlParser代码,看源码可以发现是同样是通过Digester来解析webxml的配置,下面是WebXmlParser的构造方法,可以方法跟web解析相关的rule是WebRuleSet,现在来看WebRuleSet的addRuleInstances

public WebXmlParser(boolean namespaceAware, boolean validation,
            boolean blockExternal) {
//创建web-app的Digester
        webRuleSet = new WebRuleSet(false);
        webDigester = DigesterFactory.newDigester(validation,
                namespaceAware, webRuleSet, blockExternal);
        webDigester.getParser();
//创建web-fragment的Digester
        webFragmentRuleSet = new WebRuleSet(true);
        webFragmentDigester = DigesterFactory.newDigester(validation,
                namespaceAware, webFragmentRuleSet, blockExternal);
        webFragmentDigester.getParser();
}
    //WebXml会作为根对象push进Digester类
WebRuleSet的addRuleInstances方法:
public void addRuleInstances(Digester digester) {
// SetPublicIdRule 的作用是解析到web-app或者web-fragment的时候,调用WebXml的SetPublicIdRule方法,传入Digester解析得到的publicId
        digester.addRule(fullPrefix,
                new SetPublicIdRule("setPublicId"));
// IgnoreAnnotationsRule 调用WebXml对象的setMetadataComplete,web-app标签metadata-complete的属性值作为参数
        digester.addRule(fullPrefix,
                new IgnoreAnnotationsRule());
// VersionRule调用WebXml对象的setVersion,web-app标签version属性值作为参数
        digester.addRule(fullPrefix,
                new VersionRule());
// AbsoluteOrderingRule,实例化WebXml类的absoluteOrdering 属性,什么作用后面可以看到
        digester.addRule(fullPrefix + "/absolute-ordering", absoluteOrdering);
//打印log的一个rule,如果不是fragment,则会打警告的log
        digester.addRule(fullPrefix + "/ordering", relativeOrdering);
        if (fragment) {
//解析到web-fragment/name的时候,调用WebXml的setName方法,传入name标签的body text(<name>xxxs</name>)
            digester.addRule(fullPrefix + "/name", name);
//解析到web-fragment/ ordering/after/name的時候,调用WebXml的addAfterOrdering,传入标签的body text
            digester.addCallMethod(fullPrefix + "/ordering/after/name",
                                   "addAfterOrdering", 0);
            digester.addCallMethod(fullPrefix + "/ordering/after/others",
                                   "addAfterOrderingOthers");
            digester.addCallMethod(fullPrefix + "/ordering/before/name",
                                   "addBeforeOrdering", 0);
            digester.addCallMethod(fullPrefix + "/ordering/before/others",
                                   "addBeforeOrderingOthers");
//以上同解析web-fragment/ ordering/after/name标签
        } else {
            //解析到web-xml/absolute-ordering/name,调用WebXml的addAbsoluteOrdering方法,传入标签的body text
            digester.addCallMethod(fullPrefix + "/absolute-ordering/name",
                                   "addAbsoluteOrdering", 0);
//解析到web-xml/absolute-ordering/ others,调用WebXml的addAbsoluteOrderingOthers方法,传入标签的body text
            digester.addCallMethod(fullPrefix + "/absolute-ordering/others",
                                   "addAbsoluteOrderingOthers");
//解析到web-xml/ deny-uncovered-http-methods,SetDenyUncoveredHttpMethodsRule rule调用WebXml的setDenyUncoveredHttpMethods方法,设置为true
            digester.addRule(fullPrefix + "/deny-uncovered-http-methods",
                    new SetDenyUncoveredHttpMethodsRule());
        }
//解析到web-xml(web-fragement下同)/ context-param结束标签,调用WebXml的addContextParam方法,传入之前push进的param
        digester.addCallMethod(fullPrefix + "/ context-param ",
                               "addContextParam", 2);
//解析到xx/context-param/param-name,push进digester的parameters,作为之前方法的第一个参数
        digester.addCallParam(fullPrefix + "/context-param/param-name", 0);
//解析到xx/context-param/ param-value,push进digester的parameters,作为之前方法的第二个参数
        digester.addCallParam(fullPrefix + "/context-param/param-value", 1);
//解析到xx/display-name,调用WebXml方法setDisplayName,传入标签的body text
        digester.addCallMethod(fullPrefix + "/display-name",
                               "setDisplayName", 0);
//解析到xx/ distributable,SetDistributableRule rule 调用WebXml的setDistributable,设置true
        digester.addRule(fullPrefix + "/distributable",
                         new SetDistributableRule ());
//这个是有关ejb的rule,分析ejb的时候,重点分析
        configureNamingRules(digester);

//解析到xx/ error-page,创建对象org.apache.tomcat.util.descriptor.web.ErrorPage
        digester.addObjectCreate(fullPrefix + "/error-page",
                            "org.apache.tomcat.util.descriptor.web.ErrorPage");
//解析到xx/ error-page,调用WebXml的addErrorPage,传入之前ObjectCreateRule创建的对象
        digester.addSetNext(fullPrefix + "/error-page",
                            "addErrorPage",
                            "org.apache.tomcat.util.descriptor.web.ErrorPage");
//解析到xx/error-page/error-code,调用ErrorPage的setErrorCode,传入body text
        digester.addCallMethod(fullPrefix + "/error-page/error-code",
                               "setErrorCode", 0);
//解析到xx/error-page/ exception-type,调用ErrorPage的setExceptionType,传入body text
        digester.addCallMethod(fullPrefix + "/error-page/exception-type",
                               "setExceptionType", 0);
//解析到xx/error-page/ location,调用ErrorPage的setLocation,传入body text
        digester.addCallMethod(fullPrefix + "/error-page/location",
                               "setLocation", 0);
//解析到xx/ filter,创建对象org.apache.tomcat.util.descriptor.web.FilterDef
        digester.addObjectCreate(fullPrefix + "/filter",
                             "org.apache.tomcat.util.descriptor.web.FilterDef");
//解析到xx/ filter,调用WebXml的addFilter,传入之前创建的FilterDef对象
        digester.addSetNext(fullPrefix + "/filter",
                            "addFilter",
                            "org.apache.tomcat.util.descriptor.web.FilterDef");
//解析到xx/ filter/ description,调用FilterDef的setDescription方法,传入body text
        digester.addCallMethod(fullPrefix + "/filter/description",
                               "setDescription", 0);
//解析到xx/ filter/ display-name,调用FilterDef的setDisplayName方法,传入body text
        digester.addCallMethod(fullPrefix + "/filter/display-name",
                               "setDisplayName", 0);
//解析到xx/ filter/filter-class,调用FilterDef的setFilterClass方法,传入body text
        digester.addCallMethod(fullPrefix + "/filter/filter-class",
                               "setFilterClass", 0);
//解析到xx/ filter/ filter-name,调用FilterDef的setFilterName方法,传入body text
        digester.addCallMethod(fullPrefix + "/filter/filter-name",
                               "setFilterName", 0);
//解析到xx/ filter/ icon/large-icon,调用FilterDef的setLargeIcon方法,传入body text
        digester.addCallMethod(fullPrefix + "/filter/icon/large-icon",
                               "setLargeIcon", 0);
//解析到xx/ filter/ icon/ small-icon,调用FilterDef的setSmallIcon方法,传入body text

        digester.addCallMethod(fullPrefix + "/filter/icon/small-icon",
                               "setSmallIcon", 0);
//解析到xx/ filter/ async-supported,调用FilterDef的setAsyncSupported方法,传入body text
        digester.addCallMethod(fullPrefix + "/filter/async-supported",
                "setAsyncSupported", 0);
//解析到xx/filter/init-param結束标签,调用FilterDef的addInitParameter方法,传入之前push的parameters里的参数
        digester.addCallMethod(fullPrefix + "/filter/init-param",
                               "addInitParameter", 2);
//解析到xx/filter/init-param/param-name,push进digester的parameters,作为addInitParameter的第一个参数
        digester.addCallParam(fullPrefix + "/filter/init-param/param-name",
                              0);
//解析到xx/filter/init-param/param-value,push进digester的parameters,作为addInitParameter的第二个参数
        digester.addCallParam(fullPrefix + "/filter/init-param/param-value",
                              1);
//解析到xx/filter-mapping,创建对象org.apache.tomcat.util.descriptor.web.FilterMap
        digester.addObjectCreate(fullPrefix + "/filter-mapping",
                       "org.apache.tomcat.util.descriptor.web.FilterMap");
//解析到xx/ filter-mapping,调用WebXml的addFilterMapping,传入之前创建的对象FilterMap
        digester.addSetNext(fullPrefix + "/filter-mapping",
                                 "addFilterMapping",
               "org.apache.tomcat.util.descriptor.web.FilterMap");
//解析到xx/filter-mapping/filter-name,调用FilterMap的setFilterName,传入这个标签的body text
        digester.addCallMethod(fullPrefix + "/filter-mapping/filter-name",
                               "setFilterName", 0);
//解析到xx/filter-mapping/ servlet-name,调用FilterMap的addServletName,传入这个标签的body text
        digester.addCallMethod(fullPrefix + "/filter-mapping/servlet-name",
                               "addServletName", 0);
//解析到xx/filter-mapping/ url-pattern,调用FilterMap的addURLPattern,传入这个标签的body text
        digester.addCallMethod(fullPrefix + "/filter-mapping/url-pattern",
                               "addURLPattern", 0);
//解析到xx/filter-mapping/ dispatcher,调用FilterMap的setDispatcher,传入这个标签的body text
        digester.addCallMethod(fullPrefix + "/filter-mapping/dispatcher",
                               "setDispatcher", 0);
//解析到xx/listener/listener-class,调用WebXml的addListener方法,传入标签的body text
         digester.addCallMethod(fullPrefix + "/listener/listener-class",
                                "addListener", 0);
//解析到xx/ jsp-config,SetJspConfig rule判断是否是只配置一个jsp-config
        digester.addRule(fullPrefix + "/jsp-config",
                         jspConfig);
//解析到xx/ jsp-config/jsp-property-group,创建对象org.apache.tomcat.util.descriptor.web.JspPropertyGroup
        digester.addObjectCreate(fullPrefix + "/jsp-config/jsp-property-group",
                  "org.apache.tomcat.util.descriptor.web.JspPropertyGroup");
//解析到xx/jsp-config/jsp-property-group,调用WebXml的addJspPropertyGroup,传入之前创建的对象JspPropertyGroup
        digester.addSetNext(fullPrefix + "/jsp-config/jsp-property-group",
                            "addJspPropertyGroup",
                  "org.apache.tomcat.util.descriptor.web.JspPropertyGroup");
//解析到xx/jsp-config/ jsp-property-group/deferred-syntax-allowed-as-literal,调用JspPropertyGroup的setDeferredSyntax方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/deferred-syntax-allowed-as-literal",
                               "setDeferredSyntax", 0);
//解析到xx/jsp-config/ jsp-property-group/ el-ignored,调用JspPropertyGroup的setElIgnored方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/el-ignored",
                               "setElIgnored", 0);
//解析到xx/jsp-config/ jsp-property-group/include-coda,调用JspPropertyGroup的addIncludeCoda方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/include-coda",
                               "addIncludeCoda", 0);
//解析到xx/jsp-config/ jsp-property-group/include- prelude,调用JspPropertyGroup的addIncludePrelude方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/include-prelude",
                               "addIncludePrelude", 0);
//解析到xx/jsp-config/ jsp-property-group/is-xml,调用JspPropertyGroup的setIsXml方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/is-xml",
                               "setIsXml", 0);
//解析到xx/jsp-config/ jsp-property-group/page-encoding,调用JspPropertyGroup的setPageEncoding方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/page-encoding",
                               "setPageEncoding", 0);
//解析到xx/jsp-config/ jsp-property-group/scripting-invalid,调用JspPropertyGroup的setScriptingInvalid方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/scripting-invalid",
                               "setScriptingInvalid", 0);
//解析到xx/jsp-config/ jsp-property-group/ trim-directive-whitespaces,调用JspPropertyGroup的setTrimWhitespace方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/trim-directive-whitespaces",
                               "setTrimWhitespace", 0);
//解析到xx/jsp-config/ jsp-property-group/url-pattern,调用JspPropertyGroup的addUrlPattern方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/url-pattern",
                               "addUrlPattern", 0);
//解析到xx/jsp-config/ jsp-property-group/ default-content-type,调用JspPropertyGroup的setDefaultContentType方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/default-content-type",
                               "setDefaultContentType", 0);
//解析到xx/jsp-config/ jsp-property-group/ buffer,调用JspPropertyGroup的setBuffer方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/buffer",
                               "setBuffer", 0);
//解析到xx/jsp-config/ jsp-property-group/ error-on-undeclared-namespace,调用JspPropertyGroup的setErrorOnUndeclaredNamespace方法,传入body text
        digester.addCallMethod(fullPrefix + "/jsp-config/jsp-property-group/error-on-undeclared-namespace",
                               "setErrorOnUndeclaredNamespace", 0);
//解析到xx/ login-config,SetLoginConfig rule 判断是否只有个login-config配置
        digester.addRule(fullPrefix + "/login-config",
                         loginConfig);
//解析到xx/ login-config,创建对象org.apache.tomcat.util.descriptor.web.LoginConfig
        digester.addObjectCreate(fullPrefix + "/login-config",
                          "org.apache.tomcat.util.descriptor.web.LoginConfig");
//解析到xx/ login-config,调用WebXml的setLoginConfig方法,传入之前创建的对象LoginConfig
        digester.addSetNext(fullPrefix + "/login-config",
                            "setLoginConfig",
                        "org.apache.tomcat.util.descriptor.web.LoginConfig");
//解析到xx/ login-config/ auth-method,调用对象LoginConfig的setAuthMethod,传入标签的body text
        digester.addCallMethod(fullPrefix + "/login-config/auth-method",
                               "setAuthMethod", 0);
//解析到xx/ login-config/ realm-name,调用对象LoginConfig的setRealmName,传入标签的body text
        digester.addCallMethod(fullPrefix + "/login-config/realm-name",
                               "setRealmName", 0);
//解析到xx/ login-config/ form-login-config/form-error-page,调用对象LoginConfig的setErrorPage,传入标签的body text
        digester.addCallMethod(fullPrefix + "/login-config/form-login-config/form-error-page",
                               "setErrorPage", 0);
//解析到xx/ login-config/ form-login-config/ form-login-page,调用对象LoginConfig的setLoginPage,传入标签的body text
        digester.addCallMethod(fullPrefix + "/login-config/form-login-config/form-login-page",
                               "setLoginPage", 0);
//解析到xx/ mime-mapping結束标签,调用WebXml的addMimeMapping,传入参数digester的parameters
        digester.addCallMethod(fullPrefix + "/mime-mapping",
                               "addMimeMapping", 2);
//解析到xx/ mime-mapping/ extension,push进digester的paramters(body text),作为第一个参数
        digester.addCallParam(fullPrefix + "/mime-mapping/extension", 0);
//解析到xx/ mime-mapping/ mime-type,push进digester的paramters(body text),作为第二个参数
        digester.addCallParam(fullPrefix + "/mime-mapping/mime-type", 1);
//解析到xx/ security-constraint,创建对象org.apache.tomcat.util.descriptor.web.SecurityConstraint
        digester.addObjectCreate(fullPrefix + "/security-constraint",
                 "org.apache.tomcat.util.descriptor.web.SecurityConstraint");
//解析到xx/ security-constraint,调用WebXml的addSecurityConstraint,传入对象SecurityConstraint
        digester.addSetNext(fullPrefix + "/security-constraint",
                            "addSecurityConstraint",
                     "org.apache.tomcat.util.descriptor.web.SecurityConstraint");
//解析到xx/ security-constraint/auth-constraint,SetAuthConstraintRule rule 调用SecurityConstraint的setAuthConstraint方法,设置true
        digester.addRule(fullPrefix + "/security-constraint/auth-constraint",
                         new SetAuthConstraintRule());
//解析到xx/ security-constraint/ auth-constraint/role-name,调用SecurityConstraint的addAuthRole方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-constraint/auth-constraint/role-name",
                               "addAuthRole", 0);
//解析到xx/ security-constraint/ display-name,调用SecurityConstraint的setDisplayName方法,传入标签的body text
   digester.addCallMethod(fullPrefix + "/security-constraint/display-name",
                               "setDisplayName", 0);
//解析到xx/ security-constraint/ user-data-constraint/transport-guarantee,调用SecurityConstraint的setUserConstraint方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-constraint/user-data-constraint/transport-guarantee",
                               "setUserConstraint", 0);
//解析到xx/ security-constraint/ web-resource-collection,创建对象org.apache.tomcat.util.descriptor.web.SecurityCollection
        digester.addObjectCreate(fullPrefix + "/security-constraint/web-resource-collection",
                "org.apache.tomcat.util.descriptor.web.SecurityCollection");
//解析到xx/ security-constraint/ web-resource-collection,调用SecurityConstraint的addCollection,传入之前创建的对象SecurityCollection
        digester.addSetNext(fullPrefix + "/security-constraint/web-resource-collection",
                            "addCollection",
                "org.apache.tomcat.util.descriptor.web.SecurityCollection");
//解析到xx/ security-constraint/ web-resource-collection/http-method,调用SecurityCollection的addMethod,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/http-method",
                               "addMethod", 0);
//解析到xx/ security-constraint/ web-resource-collection/ http-method-omission,调用SecurityCollection的addOmittedMethod,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/http-method-omission",
                               "addOmittedMethod", 0);
//解析到xx/ security-constraint/ web-resource-collection/url-pattern,调用SecurityCollection的addPattern,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/url-pattern",
                               "addPattern", 0);
//解析到xx/ security-constraint/ web-resource-collection/ web-resource-name,调用SecurityCollection的setName,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-constraint/web-resource-collection/web-resource-name",
                               "setName", 0);
//解析到xx/security-role/role-name,调用WebXml的addSecurityRole,传入标签的body text
        digester.addCallMethod(fullPrefix + "/security-role/role-name",
                               "addSecurityRole", 0);
//解析到xx/servlet,ServletDefCreateRule rule push进Digester对象org.apache.tomcat.util.descriptor.web. ServletDef
        digester.addRule(fullPrefix + "/servlet",
                         new ServletDefCreateRule());
//解析到xx/servlet,调用WebXml的addServlet,传入之前创建的对象ServletDef
        digester.addSetNext(fullPrefix + "/servlet",
                            "addServlet",
                      "org.apache.tomcat.util.descriptor.web.ServletDef");
//解析到xx/servlet/init-param结束标签,调用ServletDef的addInitParameter,参数是之前push进digester的parameters
        digester.addCallMethod(fullPrefix + "/servlet/init-param",
                               "addInitParameter", 2);
//解析到xx/servlet/init-param/param-name,push进digester的parameters,作为第一个参数
        digester.addCallParam(fullPrefix + "/servlet/init-param/param-name",
                              0);
//解析到xx/servlet/init-param/param-name,push进digester的parameters,作为第二个参数
        digester.addCallParam(fullPrefix + "/servlet/init-param/param-value",
                              1);
//解析到xx/servlet/ jsp-file标签,调用ServletDef的setJspFile,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/jsp-file",
                               "setJspFile", 0);
//解析到xx/servlet/ load-on-startup标签,调用ServletDef的setLoadOnStartup,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/load-on-startup",
                               "setLoadOnStartup", 0);
//解析到xx/servlet/ run-as/role-name标签,调用ServletDef的setRunAs,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/run-as/role-name",
                               "setRunAs", 0);
//解析到xx/servlet/ security-role-ref,创建对象org.apache.tomcat.util.descriptor.web.SecurityRoleRef
        digester.addObjectCreate(fullPrefix + "/servlet/security-role-ref",
                     "org.apache.tomcat.util.descriptor.web.SecurityRoleRef");
//解析到xx/servlet/ security-role-ref,调用ServletDef的addSecurityRoleRef,传入对象SecurityRoleRef
        digester.addSetNext(fullPrefix + "/servlet/security-role-ref",
                            "addSecurityRoleRef",
                       "org.apache.tomcat.util.descriptor.web.SecurityRoleRef");
//解析到xx/servlet/ security-role-ref/role-link,调用SecurityRoleRef的setLink,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/security-role-ref/role-link",
                               "setLink", 0);
//解析到xx/servlet/ security-role-ref/ role-name,调用SecurityRoleRef的setName,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/security-role-ref/role-name",
                               "setName", 0);
//解析到xx/servlet/servlet-class,调用ServletDef的setServletClass,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/servlet-class",
                              "setServletClass", 0);
//解析到xx/servlet/ servlet-name,调用ServletDef的setServletName,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/servlet-name",
                              "setServletName", 0);
//解析到xx/servlet/ multipart-config,创建org.apache.tomcat.util.descriptor.web.MultipartDef对象
        digester.addObjectCreate(fullPrefix + "/servlet/multipart-config",
                       "org.apache.tomcat.util.descriptor.web.MultipartDef");
//解析到xx/servlet/ multipart-config,调用ServletDef的setMultipartDef,传入之前创建的对象MultipartDef
        digester.addSetNext(fullPrefix + "/servlet/multipart-config",
                            "setMultipartDef",
                         "org.apache.tomcat.util.descriptor.web.MultipartDef");
//解析到xx/servlet/ multipart-config/location,调用MultipartDef的setLocation方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/multipart-config/location",
                               "setLocation", 0);
//解析到xx/servlet/ multipart-config/ max-file-size,调用MultipartDef的setMaxFileSize方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/multipart-config/max-file-size",
                               "setMaxFileSize", 0);
//解析到xx/servlet/ multipart-config/ max-request-size,调用MultipartDef的setMaxRequestSize方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/multipart-config/max-request-size",
                               "setMaxRequestSize", 0);
//解析到xx/servlet/ multipart-config/ file-size-threshold,调用MultipartDef的setFileSizeThreshold方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/multipart-config/file-size-threshold",
                               "setFileSizeThreshold", 0);
//解析到xx/servlet/async-supported,调用ServletDef的setAsyncSupported方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/async-supported",
                               "setAsyncSupported", 0);
//解析到xx/ servlet/enabled,调用ServletDef的setEnabled方法,传入标签的body text
        digester.addCallMethod(fullPrefix + "/servlet/enabled",
                               "setEnabled", 0);
//解析到xx/servlet-mapping结束标签,调用WebXml的方法addServletMapping,传入之前push 进digester的parameters,CallMethodMultiRule的第三个参数0是parameters里的param index,这个param是ArrayList
        digester.addRule(fullPrefix + "/servlet-mapping",
                               new CallMethodMultiRule("addServletMapping", 2, 0));
//解析到xx/servlet-mapping/servlet-name,push进digester的parameters,参数是servlet-name标签的body text
        digester.addCallParam(fullPrefix + "/servlet-mapping/servlet-name", 1);
//解析到xx/ servlet-mapping/url-pattern,push进digester的parameters,push进的param是ArrayList,参数0是push进parameters的参数的index
        digester.addRule(fullPrefix + "/servlet-mapping/url-pattern", new CallParamMultiRule(0));
//解析到xx/session-config,SetSessionConfig rule,判断是否只有1次配置,只能配置一个
        digester.addRule(fullPrefix + "/session-config ", sessionConfig);
//解析到xx/session-config,创建对象org.apache.tomcat.util.descriptor.web.SessionConfig
        digester.addObjectCreate(fullPrefix + "/session-config",
                        "org.apache.tomcat.util.descriptor.web.SessionConfig");
//解析到xx/session-config,调用WebXml的setSessionConfig,传入参数SessionConfig
        digester.addSetNext(fullPrefix + "/session-config", "setSessionConfig",
                        "org.apache.tomcat.util.descriptor.web.SessionConfig");
//解析到xx/session-config/ session-timeout,调用SessionConfig的setSessionTimeout,参数是标签的body text
        digester.addCallMethod(fullPrefix + "/session-config/session-timeout",
                               "setSessionTimeout", 0);
//解析到xx/ session-config/cookie-config/name,调用SessionConfig的setCookieName,参数是标签的body text
        digester.addCallMethod(fullPrefix + "/session-config/cookie-config/name",
                               "setCookieName", 0);
//解析到xx/ session-config/cookie-config/ domain,调用SessionConfig的setCookieDomain,参数是标签的body text
        digester.addCallMethod(fullPrefix + "/session-config/cookie-config/domain", "setCookieDomain", 0);
//解析到xx/ session-config/cookie-config/ path,调用SessionConfig的setCookiePath,参数是标签的body text
        digester.addCallMethod(fullPrefix + "/session-config/cookie-config/path",
                               "setCookiePath", 0);
  //解析到xx/ session-config/cookie-config/ comment,调用SessionConfig的setCookieComment,参数是标签的body text      
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/comment",
                               "setCookieComment", 0);
//解析到xx/ session-config/cookie-config/ http-only,调用SessionConfig的setCookieHttpOnly,参数是标签的body text      
        digester.addCallMethod(fullPrefix + "/session-config/cookie-config/http-only",
                               "setCookieHttpOnly", 0);
//解析到xx/ session-config/cookie-config/ secure,调用SessionConfig的setCookieSecure,参数是标签的body text   
        digester.addCallMethod(fullPrefix + "/session-config/cookie-config/secure",
                               "setCookieSecure", 0);
//解析到xx/ session-config/cookie-config/ max-age,调用SessionConfig的setCookieMaxAge,参数是标签的body text   
        digester.addCallMethod(fullPrefix + "/session-config/cookie-config/max-age",
                               "setCookieMaxAge", 0);
//解析到xx/ session-config/cookie-config/ tracking-mode,调用SessionConfig的addSessionTrackingMode,参数是标签的body text   
        digester.addCallMethod(fullPrefix + "/session-config/tracking-mode",
                               "addSessionTrackingMode", 0);

        // Taglibs pre Servlet 2.4
//解析到xx/taglib,TaglibLocationRule rule参数false表示是pre  Servlet 2.4, 2.4之前version的,WebXml必须有publicID
        digester.addRule(fullPrefix + "/taglib", new TaglibLocationRule(false));
//解析到xx/taglib结束标签,调用WebXml的addTaglib方法,传入参数是之前push进的parameters
        digester.addCallMethod(fullPrefix + "/taglib",
                               "addTaglib", 2);
//解析到xx/taglib/taglib-location,push进digester的parameters,参数是标签的body text,参数index是1
        digester.addCallParam(fullPrefix + "/taglib/taglib-location", 1);
//解析到xx/taglib/ taglib-uri,push进digester的parameters,参数是标签的body text,参数index是0
        digester.addCallParam(fullPrefix + "/taglib/taglib-uri", 0);
        // Taglibs Servlet 2.4 onwards
//解析到xx/jsp-config/taglib,TaglibLocationRule rule参数true,表示是2.4或者later的version,WebXml不能用public
        digester.addRule(fullPrefix + "/jsp-config/taglib", new TaglibLocationRule(true));
//解析到xx//jsp-config/taglib结束标签,调用WebXml的addTaglib方法,传入之前push进digester的参数
        digester.addCallMethod(fullPrefix + "/jsp-config/taglib",
                "addTaglib", 2);
//解析到xx/jsp-config/taglib/taglib-location,push进digester的parameters,作为第二个参数(标签的body text)
        digester.addCallParam(fullPrefix + "/jsp-config/taglib/taglib-location", 1);
//解析到xx/jsp-config/taglib/ taglib-uri,push进digester的parameters,作为第一个参数(标签的body text)
        digester.addCallParam(fullPrefix + "/jsp-config/taglib/taglib-uri", 0);
//解析到xx/ welcome-file-list/welcome-file的時候,调用WebXml的addWelcomeFile方法,参数是标签的body text
        digester.addCallMethod(fullPrefix + "/welcome-file-list/welcome-file",
                               "addWelcomeFile", 0);
//解析到xx/locale-encoding-mapping-list/locale-encoding-mapping结束标签,调用WebXml的addLocaleEncodingMapping,传入之前push进digester的paramters
        digester.addCallMethod(fullPrefix + "/locale-encoding-mapping-list/locale-encoding-mapping",
                              "addLocaleEncodingMapping", 2);
//解析到xx/locale-encoding-mapping-list/locale-encoding-mapping/locale,push进digester的parameters,作为第一个参数(body text)
        digester.addCallParam(fullPrefix + "/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0);
//解析到xx/locale-encoding-mapping-list/ locale-encoding-mapping/encoding,push进digester的parameters,作为第二个参数(body text)
        digester.addCallParam(fullPrefix + "/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1);
//解析到xx/post-construct结束标签,LifecycleCallbackRule rule 不能有重复的class,调用WebXml的addPostConstructMethods,传入之前push进digester的parameters
        digester.addRule(fullPrefix + "/post-construct",
                new LifecycleCallbackRule("addPostConstructMethods", 2, true));
//解析到xx/ post-construct/lifecycle-callback-class,push进digester的paramters,做为第一个参数(body text)
        digester.addCallParam(fullPrefix + "/post-construct/lifecycle-callback-class", 0);
//解析到xx/post-construct/ lifecycle-callback-method,push进digester的paramters,做为第二个参数(body text)
        digester.addCallParam(fullPrefix + "/post-construct/lifecycle-callback-method", 1);
//解析到xx/pre-destroy结束标签,LifecycleCallbackRule rule 不能有重复的class,调用WebXml的addPreDestroyMethods,传入之前push进digester的parameters
        digester.addRule(fullPrefix + "/pre-destroy",
                new LifecycleCallbackRule("addPreDestroyMethods", 2, false));
//解析到xx/pre-destroy/lifecycle-callback-class,push进digester的paramters,做为第一个参数(body text)
        digester.addCallParam(fullPrefix + "/pre-destroy/lifecycle-callback-class", 0);
//解析到xx/pre-destroy/ lifecycle-callback-method,push进digester的paramters,做为第二个参数(body text)
        digester.addCallParam(fullPrefix + "/pre-destroy/lifecycle-callback-method", 1);
}

2.   分析解析WebXmlFragment

代码片段

Set<WebXml> defaults = new HashSet<>();

defaults.add(getDefaultWebXmlFragment(webXmlParser));

这段代码执行完后,defaults里面有DefaultWebXmlconf/web.xml  or hostweb.xml.default

方法getDefaultWebXmlFragment(WebXmlParser webXmlParser)

private WebXml getDefaultWebXmlFragment(WebXmlParser webXmlParser) {
//获得container,默认应该是StandardHost
        Host host = (Host) context.getParent();
//通过host来获得cache到的DefaultWebXml实例对象
        DefaultWebXmlCacheEntry entry = hostWebXmlCache.get(host);
//获得CatalianBase/config/Web.xml的InputSource
        InputSource globalWebXml = getGlobalWebXmlSource();
//获得CatalianBase/config/engine/hostname/web.xml.default的InputSource
        InputSource hostWebXml = getHostWebXmlSource();
        long globalTimeStamp = 0;
        long hostTimeStamp = 0;
//设置global和host的webxml文件LastModified
        if (globalWebXml != null) {
            URLConnection uc = null;
            try {
                URL url = new URL(globalWebXml.getSystemId());
                uc = url.openConnection();
                globalTimeStamp = uc.getLastModified();
            } catch (IOException e) {
                globalTimeStamp = -1;
            } finally {
                if (uc != null) {
                    try {
                        uc.getInputStream().close();
                    } catch (IOException e) {
                        ExceptionUtils.handleThrowable(e);
                        globalTimeStamp = -1;
                    }
                }
            }
        }

        if (hostWebXml != null) {
            URLConnection uc = null;
            try {
                URL url = new URL(hostWebXml.getSystemId());
                uc = url.openConnection();
                hostTimeStamp = uc.getLastModified();
            } catch (IOException e) {
                hostTimeStamp = -1;
            } finally {
                if (uc != null) {
                    try {
                        uc.getInputStream().close();
                    } catch (IOException e) {
                        ExceptionUtils.handleThrowable(e);
                        hostTimeStamp = -1;
                    }
                }
            }
        }
//获取缓存的DefaultWebXml
        if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
                entry.getHostTimeStamp() == hostTimeStamp) {
            InputSourceUtil.close(globalWebXml);
            InputSourceUtil.close(hostWebXml);
            return entry.getWebXml();
        }

        synchronized (host.getPipeline()) {
            entry = hostWebXmlCache.get(host);
            if (entry != null && entry.getGlobalTimeStamp() == globalTimeStamp &&
                    entry.getHostTimeStamp() == hostTimeStamp) {
                return entry.getWebXml();
            }
//创建WebXml
            WebXml webXmlDefaultFragment = createWebXml();
//设置为true,表示每个app的xml可以覆盖defaultwebxml相同的项
            webXmlDefaultFragment.setOverridable(true);
//设置Distributable为true,否则每个app就不会合并defaultwebxml
            webXmlDefaultFragment.setDistributable(true);

//设置false,当merge defaultwebxml的时候,app未定义welcomefile文件时,才会合并默认的welcomefiles
            webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);

            if (globalWebXml == null) {
                log.info(sm.getString("contextConfig.defaultMissing"));
            } else {
//用1分析的WebRuleSet rule,将globalWebXml 作为source,digester解析得到处理后的webXmlDefaultFragment(WebXml对象)
                if (!webXmlParser.parseWebXml(
                        globalWebXml, webXmlDefaultFragment, false)) {
                    ok = false;
                }
            }
//替换当前的welcomefiles,当merge webxml到webXmlDefaultFragment时
            webXmlDefaultFragment.setReplaceWelcomeFiles(true);

//将hostWebXml作为source,digester解析得到处理后的webXmlDefaultFragment
            if (!webXmlParser.parseWebXml(
                    hostWebXml, webXmlDefaultFragment, false)) {
                ok = false;
            }

            if (globalTimeStamp != -1 && hostTimeStamp != -1) {
//设置Cache
                entry = new DefaultWebXmlCacheEntry(webXmlDefaultFragment,
                        globalTimeStamp, hostTimeStamp);
                hostWebXmlCache.put(host, entry);
            }

            return webXmlDefaultFragment;
        }
}

3.  分析解析ContextWebXml

代码片段:

//实例化一个全新的WebXml,不同于上面的defaultwebxml

WebXml webXml = createWebXml();

//获得context webxmlinputsource准备用digester来解析得到webxml

        InputSource contextWebXml = getContextWebXmlSource();

//digester解析获得前面创建的WebXml

        if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {

            ok = false;

        }

getContextWebXmlSource()方法:

    protected InputSource getContextWebXmlSource() {
        InputStream stream = null;
        InputSource source = null;
        URL url = null;

        String altDDName = null;

            // ServletContext会单独分析,现在只要知道它是一个app的上下文环境
        ServletContext servletContext = context.getServletContext();
        try {
            if (servletContext != null) {
                altDDName = (String)servletContext.getAttribute(Globals.ALT_DD_ATTR);
                if (altDDName != null) {
// 有org.apache.catalina.deploy.alt_dd对应的value作为source
                    try {
                        stream = new FileInputStream(altDDName);
                        url = new File(altDDName).toURI().toURL();
                    } catch (FileNotFoundException e) {
                        log.error(sm.getString("contextConfig.altDDNotFound",
                                               altDDName));
                    } catch (MalformedURLException e) {
                        log.error(sm.getString("contextConfig.applicationUrl"));
                    }
                }
                else {
//没有org.apache.catalina.deploy.alt_dd对应的value,则使用……/WEB-INF/web.xml作为source
 stream = servletContext.getResourceAsStream
                        (Constants.ApplicationWebXml);
                    try {
                        url = servletContext.getResource(
                                Constants.ApplicationWebXml);
                    } catch (MalformedURLException e) {
                        log.error(sm.getString("contextConfig.applicationUrl"));
                    }
                }
            }
            if (stream == null || url == null) {
                if (log.isDebugEnabled()) {
                    log.debug(sm.getString("contextConfig.applicationMissing") + " " + context);
                }
            } else {
                source = new InputSource(url.toExternalForm());
                source.setByteStream(stream);
            }
        }
………………….
        return source;
}

4.分析step1

代码片段:

Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);

 

processJarsForWebFragments方法:

protected Map<String,WebXml> processJarsForWebFragments(WebXml application, WebXmlParser webXmlParser) {
//获得JarScanner默认是StandardJarScanner
        JarScanner jarScanner = context.getJarScanner();
        boolean delegate = false;
        if (context instanceof StandardContext) {
            delegate = ((StandardContext) context).getDelegate();
        }
        boolean parseRequired = true;
        Set<String> absoluteOrder = application.getAbsoluteOrdering();
        if (absoluteOrder != null && absoluteOrder.isEmpty() &&
                !context.getXmlValidation()) {
            parseRequired = false;
        }
//StandardJarScanner扫描开始
        FragmentJarScannerCallback callback =
                new FragmentJarScannerCallback(webXmlParser, delegate, parseRequired);
        jarScanner.scan(JarScanType.PLUGGABILITY,
                context.getServletContext(), callback);
        if (!callback.isOk()) {
            ok = false;
        }
        return callback.getFragments();
}

StandardJarScannerscan方法:

  a.      扫描appWEB-INF/lib下的jar包,解析jar包里面的META-INF/web-fragment.xmlFragmentJarScannerCallback scan解析fragments.put(fragment.getName(),fragment)

  b.      扫描app /WEB-INF/classes 下的META-INF,如果不为空,调用callbackscanWebInfClasses

  c.       扫描contextclassloader以及classloader继承链上的classloadersearchpath上的jar包,解析jar包里面的META-INF/web-  fragment.xmlFragmentJarScannerCallback scan解析fragments.put(fragment.getName(),fragment)

 

5.分析step2

代码片段:

Set<WebXml> orderedFragments = null;

orderedFragments =

          WebXml.orderWebFragments(webXml, fragments, sContext);

WebXml进行排序

 

6.分析step3

代码片段:

if (ok) {

processServletContainerInitializers();

}

processServletContainerInitializers方法:

protected void processServletContainerInitializers() {

        List<ServletContainerInitializer> detectedScis;
        try {
//app的classloader加载xxx/META-INF/services/ ServletContainerInitializer资源,读取资源里面的ServletContainerInitializer配置,以#分割,然后classloader反射实例化ServletContainerInitializer(detectedScis)
// WebappServiceLoader类load方法
            WebappServiceLoader<ServletContainerInitializer> loader = new WebappServiceLoader<>(context);
            detectedScis = loader.load(ServletContainerInitializer.class);
        } catch (IOException e) {
            log.error(sm.getString(
                    "contextConfig.servletContainerInitializerFail",
                    context.getName()),
                e);
            ok = false;
            return;
        }

        for (ServletContainerInitializer sci : detectedScis) {
//填充initializerClassMap
            initializerClassMap.put(sci, new HashSet<Class<?>>());
            HandlesTypes ht;
            try {
//获得sci的HandlesTypes annotation
                ht = sci.getClass().getAnnotation(HandlesTypes.class);
            } catch (Exception e) {
                if (log.isDebugEnabled()) {
                    log.info(sm.getString("contextConfig.sci.debug",
                            sci.getClass().getName()),
                            e);
                } else {
                    log.info(sm.getString("contextConfig.sci.info",
                            sci.getClass().getName()));
                }
                continue;
            }
            if (ht == null) {
                continue;
            }
// HandlesTypes annotation配置的class[]
            Class<?>[] types = ht.value();
            if (types == null) {
                continue;
            }
//填充typeInitializerMap,key是class[]里面配置的type,value是ServletContainerInitializer对象
            for (Class<?> type : types) {
                if (type.isAnnotation()) {
                    handlesTypesAnnotations = true;
                } else {
                    handlesTypesNonAnnotations = true;
                }
                Set<ServletContainerInitializer> scis =
                        typeInitializerMap.get(type);
                if (scis == null) {
                    scis = new HashSet<>();
                    typeInitializerMap.put(type, scis);
                }
                scis.add(sci);
            }
        }
}

WebappServiceLoaderload方法

public List<T> load(Class<T> serviceType) throws IOException {
        String configFile = SERVICES + serviceType.getName();

        LinkedHashSet<String> applicationServicesFound = new LinkedHashSet<>();
        LinkedHashSet<String> containerServicesFound = new LinkedHashSet<>();

        ClassLoader loader = servletContext.getClassLoader();

        @SuppressWarnings("unchecked")
        List<String> orderedLibs =
                (List<String>) servletContext.getAttribute(ServletContext.ORDERED_LIBS);
        if (orderedLibs != null) {
//如果配置了javax.servlet.context.orderedLibs key的value,迭代实例化applicationServicesFound,source是/WEB-INF/lib下的jar包里面的META-INF/services/ ServletContainerInitializer
            for (String lib : orderedLibs) {
                URL jarUrl = servletContext.getResource(LIB + lib);
                if (jarUrl == null) {
                    // should not happen, just ignore
                    continue;
                }

                String base = jarUrl.toExternalForm();
                URL url;
                if (base.endsWith("/")) {
                    url = new URL(base + configFile);
                } else {
                    url = JarFactory.getJarEntryURL(jarUrl, configFile);
                }
                try {
                    parseConfigFile(applicationServicesFound, url);
                } catch (FileNotFoundException e) {
                    // no provider file found, this is OK
                }
            }
            loader = context.getParentClassLoader();
        }
//实例化containerServicesFound,source是META-INF/services/ ServletContainerInitializer
        Enumeration<URL> resources;
        if (loader == null) {
            resources = ClassLoader.getSystemResources(configFile);
        } else {
            resources = loader.getResources(configFile);
        }
        while (resources.hasMoreElements()) {
            parseConfigFile(containerServicesFound, resources.nextElement());
        }


//filter
        if (containerSciFilterPattern != null) {
            Iterator<String> iter = containerServicesFound.iterator();
            while (iter.hasNext()) {
                if (containerSciFilterPattern.matcher(iter.next()).find()) {
                    iter.remove();
                }
            }
        }
        containerServicesFound.addAll(applicationServicesFound);

        if (containerServicesFound.isEmpty()) {
            return Collections.emptyList();
        }
//通过containerServicesFound读取到的ServletContainerInitializer配置信息,来实例化ServletContainerInitializer
        return loadServices(serviceType, containerServicesFound);
    }

7.    分析step4

代码片段:

if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {

    //webXmlmetadataComplete flase或者配置了ServletContainerInitializer相关的信息

   Map<String,JavaClassCacheEntry> javaClassCache = new HashMap<>();

     if (ok) {

            WebResource[] webResources =

                        context.getResources().listResources("/WEB-INF/classes");

                for (WebResource webResource : webResources) {

//循环迭代处理/WEB-INF/classes下的资源

                    if ("META-INF".equals(webResource.getName())) {

                        //不处理META-INF

continue;

                    }

             processAnnotationsWebResource(webResource, webXml,

                    webXml.isMetadataComplete(), javaClassCache);

                }

 

            }

 

processAnnotationsWebResource方法:

protected void processAnnotationsWebResource(WebResource webResource,
            WebXml fragment, boolean handlesTypesOnly,
            Map<String,JavaClassCacheEntry> javaClassCache) {

        if (webResource.isDirectory()) {
//如果webResource是目录,将递归调用processAnnotationsWebResource
            WebResource[] webResources =
              webResource.getWebResourceRoot().listResources(
                            webResource.getWebappPath());
           ………………..
                for (WebResource r : webResources) {
                    processAnnotationsWebResource(r, fragment, handlesTypesOnly, javaClassCache);
                }
            }
        } else if (webResource.isFile() &&
                webResource.getName().endsWith(".class")) {
//如果是file并且是class文件,调用processAnnotationsStream
            try (InputStream is = webResource.getInputStream()) {
                processAnnotationsStream(is, fragment, handlesTypesOnly, javaClassCache);
            } catch (IOException e) {
                log.error(sm.getString("contextConfig.inputStreamWebResource",
                        webResource.getWebappPath()),e);
            } catch (ClassFormatException e) {
                log.error(sm.getString("contextConfig.inputStreamWebResource",
                        webResource.getWebappPath()),e);
            }
        }
    }
看processAnnotationsStream源码片段
protected void processAnnotationsStream(InputStream is, WebXml fragment,
            boolean handlesTypesOnly, Map<String,JavaClassCacheEntry> javaClassCache)
            throws ClassFormatException, IOException {
…………..
            String className = clazz.getClassName();
            for (AnnotationEntry ae : annotationsEntries) {
   String type = ae.getAnnotationType();
if ("Ljavax/servlet/annotation/WebServlet;".equals(type)) {
                    processAnnotationWebServlet(className, ae, fragment);
}else if ("Ljavax/servlet/annotation/WebFilter;".equals(type)) {
     processAnnotationWebFilter(className, ae, fragment);
}else if ("Ljavax/servlet/annotation/WebListener;".equals(type)) {
                    fragment.addListener(className);
     } else {
                    // Unknown annotation - ignore
                }
            }
        }
    }

最后会根据注解不同,调用不同的方法

       WebServlet--------------à processAnnotationWebServlet

       WebFilter----------------à processAnnotationWebFilter

       WebListener------------à fragment.addListener

      

       processAnnotationWebServlet 方法:

解析WebServlet注解相关信息,创建ServletDef对象,将相关属性设置进ServletDef,最后addwebXmlservletDefs 相关代码片段

for (ElementValuePair evp : evps) {

            String name = evp.getNameString();

            if ("value".equals(name) || "urlPatterns".equals(name)) {

                if (urlPatternsSet) {

                    throw new IllegalArgumentException(sm.getString(

                            "contextConfig.urlPatternValue", "WebServlet", className));

                }

                urlPatternsSet = true;

                urlPatterns = processAnnotationsStringArray(evp.getValue());

            } else if ("description".equals(name)) {

                if (servletDef.getDescription() == null) {

                    servletDef.setDescription(evp.getValue().stringifyValue());

                }

            } else if ("displayName".equals(name)) {

                if (servletDef.getDisplayName() == null) {

                    servletDef.setDisplayName(evp.getValue().stringifyValue());

                }

            } else if ("largeIcon".equals(name)) {

                if (servletDef.getLargeIcon() == null) {

                    servletDef.setLargeIcon(evp.getValue().stringifyValue());

                }

            } else if ("smallIcon".equals(name)) {

                if (servletDef.getSmallIcon() == null) {

                    servletDef.setSmallIcon(evp.getValue().stringifyValue());

                }

            } else if ("asyncSupported".equals(name)) {

                if (servletDef.getAsyncSupported() == null) {

                    servletDef.setAsyncSupported(evp.getValue()

                            .stringifyValue());

                }

            } else if ("loadOnStartup".equals(name)) {

              …………….

            } else if ("initParams".equals(name)) {

                ………………

        }

}

}

processAnnotationWebFilter方法:

processAnnotationWebServlet方法类似,不过是filterDef

 

调用fragment.addListener方法:

WebXmladdListener方法

public void addListener(String className) {

        listeners.add(className);

 

    }

 

8.  分析step5

代码片段:

if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {

           //st ep4……

//step5step4类似,都是要解析class上的注解,@WebServlet@WebFilter@WebListener,不同于step4step5解析的是step1步骤下解析的webfragment

            if (ok) {

                processAnnotations(

                        orderedFragments, webXml.isMetadataComplete(), javaClassCache);

            }

 

            // Cache, if used, is no longer required so clear it

            javaClassCache.clear();

 

        }

 

9.分析step6~9

代码片段:

 

if (!webXml.isMetadataComplete()) {

            // Step 6. Merge web-fragment.xml files into the main web.xml

            // file.

//将前面分析的主webxmlstep1解析得到的webxml merge,具体逻辑可以以后再看

            if (ok) {

                ok = webXml.merge(orderedFragments);

            }

 

            // Step 7. Apply global defaults

            // Have to merge defaults before JSP conversion since defaults

            // provide JSP servlet definition

//将前面分析的主webxml与前面分析的defaults webxml,具体逻辑可以以后再看.

            webXml.merge(defaults);

 

            // Step 8. Convert explicitly mentioned jsps to servlets

            if (ok) {

//主要是设置org.apache.jasper.servlet.JspServletServletDef

                convertJsps(webXml);

            }

            // Step 9. Apply merged web.xml to Context

            if (ok) {

//webXml存储的某些配置信息传递给当前的StandardContext

                configureContext(webXml);

            }

        } else {

            webXml.merge(defaults);

            convertJsps(webXml);

            configureContext(webXml);

        }

 

 10.分析step10

代码片段:

if (ok) {

//解析WEB-INF/classes/META-INF/下的静态资源,以后可以分析,静态分析跟WebResourceRootWebResource类有关

            // Spec does not define an order.

            // Use ordered JARs followed by remaining JARs

            Set<WebXml> resourceJars = new LinkedHashSet<>();

            for (WebXml fragment : orderedFragments) {

                resourceJars.add(fragment);

            }

            for (WebXml fragment : fragments.values()) {

                if (!resourceJars.contains(fragment)) {

                    resourceJars.add(fragment);

                }

            }

            processResourceJARs(resourceJars);

            // See also StandardContext.resourcesStart() for

            // WEB-INF/classes/META-INF/resources configuration

 

        }

 

11.分析step11

代码片段:将webxmlServletContainerInitializer同步进contextinitializerClassMap是在checkHandlesTypes方法填充,xxx/WEB-INF/classes下的资源

if (ok) {

            for (Map.Entry<ServletContainerInitializer,

                    Set<Class<?>>> entry :

                        initializerClassMap.entrySet()) {

                if (entry.getValue().isEmpty()) {

                    context.addServletContainerInitializer(

                            entry.getKey(), null);

                } else {

                    context.addServletContainerInitializer(

                            entry.getKey(), entry.getValue());

                }

            }

 

        }

 

总结:这个是初步的分析,随着以后整个流程的走通,再去分析最后涉及到的细节,ConfigureStart方法是在beforeStart之后和start之前触发, StandardContextstartInternal方法就可以用到ConfigureStart方法中解析得到的信息,webconfig方法,就如它的名字,读取tomcatwebxml的配置,将defaultweb(config/webxml)或者host默认的webxml合并到当前app的主webxml,读取META-INF WEB-INF下的配置,比如ServletContainerInitializer,注解@WebServlet@WebFilter@WebListener等信息来填充WebXmlServletDefFilterDef etc.),最后将WebXml的信息设置给当前的StandardContext以供后面使用

posted @ 2017-11-26 16:54  tom是cat  阅读(245)  评论(0编辑  收藏  举报