先码后看 Tomcat是怎么启动容器的——web.xml篇 侵立删

转自:http://tyrion.iteye.com/blog/1944144


前一篇文章讲了org.apache.catalina.startup.HostConfig的lifecycleEvent方法中所做的事情。最后看到在Tomcat启动时或启动后(后台线程定时扫描)会调用HostConfig类的deployApps方法:

Java代码   收藏代码
  1. /** 
  2.  * Deploy applications for any directories or WAR files that are found 
  3.  * in our "application root" directory. 
  4.  */  
  5. protected void deployApps() {  
  6.   
  7.     File appBase = appBase();  
  8.     File configBase = configBase();  
  9.     String[] filteredAppPaths = filterAppPaths(appBase.list());  
  10.     // Deploy XML descriptors from configBase  
  11.     deployDescriptors(configBase, configBase.list());  
  12.     // Deploy WARs  
  13.     deployWARs(appBase, filteredAppPaths);  
  14.     // Deploy expanded folders  
  15.     deployDirectories(appBase, filteredAppPaths);  
  16.   
  17. }  

可以看到这里部署应用有三种方式:XML文件描述符、WAR包、文件目录。三种方式部署的总体流程很相似,都是一个web应用分配一个线程来处理,这里统一放到与Host内部的线程池对象中(startStopExecutor),所以有时会看到在默认配置下Tomcat启动后可能有一个叫“-startStop-”的线程还会运行一段时间才结束。但浏览这三种部署方式的实现代码,里面都是构建一个Context对象,并将构建好的Context对象与Host组件关联起来(即调用host.addChild(context)这句,具体代码在HostConfig类的deployDescriptor(ContextName cn, File contextXml)、deployDirectory(ContextName cn, File dir)、deployWAR(ContextName cn, File war)三个方法中,这里不再贴出代码来详细分析)。

前一篇文章只分析到这步,可以看出与一个web应用相对应的一个Context对象已经构建出来了,但如果容器只执行到这里根本无法响应一个浏览器的一次请求。就web服务器的实现来看一次请求过来除了需要根据内部Context构建找到这次请求访问的web应用具体所对应的Context对象,还需要包含web应用中具体的哪个Servlet来处理这次请求,中间是否还需要执行相应的过滤器(filter)、监听器(listener)等,做过java的web开发的都知道,这些信息是配置在一个web应用的WEB-INF\web.xml文件的(servlet3中已经支持将这些配置信息放到Java文件的注解中,但万变不离其宗,总归要在web应用的某个地方说明,并在容器启动时加载,这样才能真正提供web服务,响应请求)。

 

看到这里可以猜到Tomcat容器加载web应用时必定会有对于每个应用的web.xml文件的解析过程,本文就来看看这个解析过程。

 

在本文开头提到的三种部署应用的实现代码中有一些共通的代码,这里摘出来说明一下:

Java代码   收藏代码
  1. Class<?> clazz = Class.forName(host.getConfigClass());  
  2. LifecycleListener listener =  
  3.     (LifecycleListener) clazz.newInstance();  
  4. context.addLifecycleListener(listener);  
Java代码   收藏代码
  1. host.addChild(context);  

第一段是在所有Context对象构建时会添加一个监听器,这里监听器的类名是StandardHost类的实例变量configClass,其默认值就是org.apache.catalina.startup.ContextConfig。第二段是将当前构建的Context对象添加到父容器Host对象中。

先看下StandardHost的addChild方法的实现:

Java代码   收藏代码
  1. public void addChild(Container child) {  
  2.   
  3.     child.addLifecycleListener(new MemoryLeakTrackingListener());  
  4.   
  5.     if (!(child instanceof Context))  
  6.         throw new IllegalArgumentException  
  7.             (sm.getString("standardHost.notContext"));  
  8.     super.addChild(child);  
  9.   
  10. }  

可以看到这段代码最后调用了父类的addChild方法:

Java代码   收藏代码
  1. public void addChild(Container child) {  
  2.     if (Globals.IS_SECURITY_ENABLED) {  
  3.         PrivilegedAction<Void> dp =  
  4.             new PrivilegedAddChild(child);  
  5.         AccessController.doPrivileged(dp);  
  6.     } else {  
  7.         addChildInternal(child);  
  8.     }  
  9. }  

这里看下addChildInternal方法的实现:

Java代码   收藏代码
  1. private void addChildInternal(Container child) {  
  2.   
  3.     if( log.isDebugEnabled() )  
  4.         log.debug("Add child " + child + " " + this);  
  5.     synchronized(children) {  
  6.         if (children.get(child.getName()) != null)  
  7.             throw new IllegalArgumentException("addChild:  Child name '" +  
  8.                                                child.getName() +  
  9.                                                "' is not unique");  
  10.         child.setParent(this);  // May throw IAE  
  11.         children.put(child.getName(), child);  
  12.     }  
  13.   
  14.     // Start child  
  15.     // Don't do this inside sync block - start can be a slow process and  
  16.     // locking the children object can cause problems elsewhere  
  17.     if ((getState().isAvailable() ||  
  18.             LifecycleState.STARTING_PREP.equals(getState())) &&  
  19.             startChildren) {  
  20.         try {  
  21.             child.start();  
  22.         } catch (LifecycleException e) {  
  23.             log.error("ContainerBase.addChild: start: ", e);  
  24.             throw new IllegalStateException  
  25.                 ("ContainerBase.addChild: start: " + e);  
  26.         }  
  27.     }  
  28.   
  29.     fireContainerEvent(ADD_CHILD_EVENT, child);  
  30. }  

可以看到会调用子容器的start方法,就是指调用StandardContext的start方法。

即给host对象添加子容器时将会调用子容器的start方法,按照前面文章的分析,调用StandardContext的start方法最终会调用org.apache.catalina.core.StandardContext类的startInternal方法(该方法代码较长,建议自己阅读,不再贴出),这里将会发布一系列事件,按调用前后顺序这些事件包括:BEFORE_INIT_EVENT、AFTER_INIT_EVENT、BEFORE_START_EVENT、CONFIGURE_START_EVENT、START_EVENT、AFTER_START_EVENT。

 

前面提到在构建Context对象时都会注册一个监听器org.apache.catalina.startup.ContextConfig,看下这个类的lifecycleEvent方法中(为什么会执行这个方法可以看本博文章的分析)监听了哪些事件:

Java代码   收藏代码
  1. /** 
  2.  * Process events for an associated Context. 
  3.  * 
  4.  * @param event The lifecycle event that has occurred 
  5.  */  
  6. @Override  
  7. public void lifecycleEvent(LifecycleEvent event) {  
  8.   
  9.     // Identify the context we are associated with  
  10.     try {  
  11.         context = (Context) event.getLifecycle();  
  12.     } catch (ClassCastException e) {  
  13.         log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e);  
  14.         return;  
  15.     }  
  16.   
  17.     // Process the event that has occurred  
  18.     if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {  
  19.         configureStart();  
  20.     } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {  
  21.         beforeStart();  
  22.     } else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {  
  23.         // Restore docBase for management tools  
  24.         if (originalDocBase != null) {  
  25.             context.setDocBase(originalDocBase);  
  26.         }  
  27.     } else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {  
  28.         configureStop();  
  29.     } else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {  
  30.         init();  
  31.     } else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {  
  32.         destroy();  
  33.     }  
  34.   
  35. }  

与Context的start方法调用相关的事件监听前后顺序为:AFTER_INIT_EVENT(执行init方法)、BEFORE_START_EVENT(执行beforeStart方法)、CONFIGURE_START_EVENT(执行configureStart方法)。

在configureStart方法将直接调用webConfig方法,正是在这个方法中将会解析web.xml文件:

Java代码   收藏代码
  1. /** 
  2.  * Scan the web.xml files that apply to the web application and merge them 
  3.  * using the rules defined in the spec. For the global web.xml files, 
  4.  * where there is duplicate configuration, the most specific level wins. ie 
  5.  * an application's web.xml takes precedence over the host level or global 
  6.  * web.xml file. 
  7.  */  
  8. protected void webConfig() {  
  9.     /* 
  10.      * Anything and everything can override the global and host defaults. 
  11.      * This is implemented in two parts 
  12.      * - Handle as a web fragment that gets added after everything else so 
  13.      *   everything else takes priority 
  14.      * - Mark Servlets as overridable so SCI configuration can replace 
  15.      *   configuration from the defaults 
  16.      */  
  17.   
  18.     /* 
  19.      * The rules for annotation scanning are not as clear-cut as one might 
  20.      * think. Tomcat implements the following process: 
  21.      * - As per SRV.1.6.2, Tomcat will scan for annotations regardless of 
  22.      *   which Servlet spec version is declared in web.xml. The EG has 
  23.      *   confirmed this is the expected behaviour. 
  24.      * - As per http://java.net/jira/browse/SERVLET_SPEC-36, if the main 
  25.      *   web.xml is marked as metadata-complete, JARs are still processed 
  26.      *   for SCIs. 
  27.      * - If metadata-complete=true and an absolute ordering is specified, 
  28.      *   JARs excluded from the ordering are also excluded from the SCI 
  29.      *   processing. 
  30.      * - If an SCI has a @HandlesType annotation then all classes (except 
  31.      *   those in JARs excluded from an absolute ordering) need to be 
  32.      *   scanned to check if they match. 
  33.      */  
  34.     Set<WebXml> defaults = new HashSet<WebXml>();  
  35.     defaults.add(getDefaultWebXmlFragment());  
  36.   
  37.     WebXml webXml = createWebXml();  
  38.   
  39.     // Parse context level web.xml  
  40.     InputSource contextWebXml = getContextWebXmlSource();  
  41.     parseWebXml(contextWebXml, webXml, false);  
  42.   
  43.     ServletContext sContext = context.getServletContext();  
  44.   
  45.     // Ordering is important here  
  46.   
  47.     // Step 1. Identify all the JARs packaged with the application  
  48.     // If the JARs have a web-fragment.xml it will be parsed at this  
  49.     // point.  
  50.     Map<String,WebXml> fragments = processJarsForWebFragments();  
  51.   
  52.     // Step 2. Order the fragments.  
  53.     Set<WebXml> orderedFragments = null;  
  54.     orderedFragments =  
  55.             WebXml.orderWebFragments(webXml, fragments, sContext);  
  56.   
  57.     // Step 3. Look for ServletContainerInitializer implementations  
  58.     if (ok) {  
  59.         processServletContainerInitializers(orderedFragments);  
  60.     }  
  61.   
  62.     if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {  
  63.         // Step 4. Process /WEB-INF/classes for annotations  
  64.         if (ok) {  
  65.             // Hack required by Eclipse's "serve modules without  
  66.             // publishing" feature since this backs WEB-INF/classes by  
  67.             // multiple locations rather than one.  
  68.             NamingEnumeration<Binding> listBindings = null;  
  69.             try {  
  70.                 try {  
  71.                     listBindings = context.getResources().listBindings(  
  72.                             "/WEB-INF/classes");  
  73.                 } catch (NameNotFoundException ignore) {  
  74.                     // Safe to ignore  
  75.                 }  
  76.                 while (listBindings != null &&  
  77.                         listBindings.hasMoreElements()) {  
  78.                     Binding binding = listBindings.nextElement();  
  79.                     if (binding.getObject() instanceof FileDirContext) {  
  80.                         File webInfClassDir = new File(  
  81.                                 ((FileDirContext) binding.getObject()).getDocBase());  
  82.                         processAnnotationsFile(webInfClassDir, webXml,  
  83.                                 webXml.isMetadataComplete());  
  84.                     } else {  
  85.                         String resource =  
  86.                                 "/WEB-INF/classes/" + binding.getName();  
  87.                         try {  
  88.                             URL url = sContext.getResource(resource);  
  89.                             processAnnotationsUrl(url, webXml,  
  90.                                     webXml.isMetadataComplete());  
  91.                         } catch (MalformedURLException e) {  
  92.                             log.error(sm.getString(  
  93.                                     "contextConfig.webinfClassesUrl",  
  94.                                     resource), e);  
  95.                         }  
  96.                     }  
  97.                 }  
  98.             } catch (NamingException e) {  
  99.                 log.error(sm.getString(  
  100.                         "contextConfig.webinfClassesUrl",  
  101.                         "/WEB-INF/classes"), e);  
  102.             }  
  103.         }  
  104.   
  105.         // Step 5. Process JARs for annotations - only need to process  
  106.         // those fragments we are going to use  
  107.         if (ok) {  
  108.             processAnnotations(  
  109.                     orderedFragments, webXml.isMetadataComplete());  
  110.         }  
  111.   
  112.         // Cache, if used, is no longer required so clear it  
  113.         javaClassCache.clear();  
  114.     }  
  115.   
  116.     if (!webXml.isMetadataComplete()) {  
  117.         // Step 6. Merge web-fragment.xml files into the main web.xml  
  118.         // file.  
  119.         if (ok) {  
  120.             ok = webXml.merge(orderedFragments);  
  121.         }  
  122.   
  123.         // Step 7. Apply global defaults  
  124.         // Have to merge defaults before JSP conversion since defaults  
  125.         // provide JSP servlet definition.  
  126.         webXml.merge(defaults);  
  127.   
  128.         // Step 8. Convert explicitly mentioned jsps to servlets  
  129.         if (ok) {  
  130.             convertJsps(webXml);  
  131.         }  
  132.   
  133.         // Step 9. Apply merged web.xml to Context  
  134.         if (ok) {  
  135.             webXml.configureContext(context);  
  136.         }  
  137.     } else {  
  138.         webXml.merge(defaults);  
  139.         convertJsps(webXml);  
  140.         webXml.configureContext(context);  
  141.     }  
  142.   
  143.     // Step 9a. Make the merged web.xml available to other  
  144.     // components, specifically Jasper, to save those components  
  145.     // from having to re-generate it.  
  146.     // TODO Use a ServletContainerInitializer for Jasper  
  147.     String mergedWebXml = webXml.toXml();  
  148.     sContext.setAttribute(  
  149.            org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,  
  150.            mergedWebXml);  
  151.     if (context.getLogEffectiveWebXml()) {  
  152.         log.info("web.xml:\n" + mergedWebXml);  
  153.     }  
  154.   
  155.     // Always need to look for static resources  
  156.     // Step 10. Look for static resources packaged in JARs  
  157.     if (ok) {  
  158.         // Spec does not define an order.  
  159.         // Use ordered JARs followed by remaining JARs  
  160.         Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();  
  161.         if (orderedFragments != null) {  
  162.             for (WebXml fragment : orderedFragments) {  
  163.                 resourceJars.add(fragment);  
  164.             }  
  165.         }  
  166.         for (WebXml fragment : fragments.values()) {  
  167.             if (!resourceJars.contains(fragment)) {  
  168.                 resourceJars.add(fragment);  
  169.             }  
  170.         }  
  171.         processResourceJARs(resourceJars);  
  172.         // See also StandardContext.resourcesStart() for  
  173.         // WEB-INF/classes/META-INF/resources configuration  
  174.     }  
  175.   
  176.     // Step 11. Apply the ServletContainerInitializer config to the  
  177.     // context  
  178.     if (ok) {  
  179.         for (Map.Entry<ServletContainerInitializer,  
  180.                 Set<Class<?>>> entry :  
  181.                     initializerClassMap.entrySet()) {  
  182.             if (entry.getValue().isEmpty()) {  
  183.                 context.addServletContainerInitializer(  
  184.                         entry.getKey(), null);  
  185.             } else {  
  186.                 context.addServletContainerInitializer(  
  187.                         entry.getKey(), entry.getValue());  
  188.             }  
  189.         }  
  190.     }  
  191. }  

这个方法里面做的事情,在英文注释中说的很清楚了,概括起来包括合并Tomcat全局web.xml、当前应用中的web.xml、web-fragment.xml和web应用的注解中的配置信息,并将解析出的各种配置信息(如servlet配置、filter配置等)关联到Context对象中(在上面的代码第140行:webXml.configureContext(context))。

看下configureContext方法:

Java代码   收藏代码
  1. /** 
  2.  * Configure a {@link Context} using the stored web.xml representation. 
  3.  * 
  4.  * @param context   The context to be configured 
  5.  */  
  6. public void configureContext(Context context) {  
  7.     // As far as possible, process in alphabetical order so it is easy to  
  8.     // check everything is present  
  9.     // Some validation depends on correct public ID  
  10.     context.setPublicId(publicId);  
  11.   
  12.     // Everything else in order  
  13.     context.setEffectiveMajorVersion(getMajorVersion());  
  14.     context.setEffectiveMinorVersion(getMinorVersion());  
  15.   
  16.     for (Entry<String, String> entry : contextParams.entrySet()) {  
  17.         context.addParameter(entry.getKey(), entry.getValue());  
  18.     }  
  19.     context.setDisplayName(displayName);  
  20.     context.setDistributable(distributable);  
  21.     for (ContextLocalEjb ejbLocalRef : ejbLocalRefs.values()) {  
  22.         context.getNamingResources().addLocalEjb(ejbLocalRef);  
  23.     }  
  24.     for (ContextEjb ejbRef : ejbRefs.values()) {  
  25.         context.getNamingResources().addEjb(ejbRef);  
  26.     }  
  27.     for (ContextEnvironment environment : envEntries.values()) {  
  28.         context.getNamingResources().addEnvironment(environment);  
  29.     }  
  30.     for (ErrorPage errorPage : errorPages.values()) {  
  31.         context.addErrorPage(errorPage);  
  32.     }  
  33.     for (FilterDef filter : filters.values()) {  
  34.         if (filter.getAsyncSupported() == null) {  
  35.             filter.setAsyncSupported("false");  
  36.         }  
  37.         context.addFilterDef(filter);  
  38.     }  
  39.     for (FilterMap filterMap : filterMaps) {  
  40.         context.addFilterMap(filterMap);  
  41.     }  
  42.     for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) {  
  43.         JspPropertyGroupDescriptor descriptor =  
  44.             new ApplicationJspPropertyGroupDescriptor(jspPropertyGroup);  
  45.         context.getJspConfigDescriptor().getJspPropertyGroups().add(  
  46.                 descriptor);  
  47.     }  
  48.     for (String listener : listeners) {  
  49.         context.addApplicationListener(  
  50.                 new ApplicationListener(listener, false));  
  51.     }  
  52.     for (Entry<String, String> entry : localeEncodingMappings.entrySet()) {  
  53.         context.addLocaleEncodingMappingParameter(entry.getKey(),  
  54.                 entry.getValue());  
  55.     }  
  56.     // Prevents IAE  
  57.     if (loginConfig != null) {  
  58.         context.setLoginConfig(loginConfig);  
  59.     }  
  60.     for (MessageDestinationRef mdr : messageDestinationRefs.values()) {  
  61.         context.getNamingResources().addMessageDestinationRef(mdr);  
  62.     }  
  63.   
  64.     // messageDestinations were ignored in Tomcat 6, so ignore here  
  65.   
  66.     context.setIgnoreAnnotations(metadataComplete);  
  67.     for (Entry<String, String> entry : mimeMappings.entrySet()) {  
  68.         context.addMimeMapping(entry.getKey(), entry.getValue());  
  69.     }  
  70.     // Name is just used for ordering  
  71.     for (ContextResourceEnvRef resource : resourceEnvRefs.values()) {  
  72.         context.getNamingResources().addResourceEnvRef(resource);  
  73.     }  
  74.     for (ContextResource resource : resourceRefs.values()) {  
  75.         context.getNamingResources().addResource(resource);  
  76.     }  
  77.     for (SecurityConstraint constraint : securityConstraints) {  
  78.         context.addConstraint(constraint);  
  79.     }  
  80.     for (String role : securityRoles) {  
  81.         context.addSecurityRole(role);  
  82.     }  
  83.     for (ContextService service : serviceRefs.values()) {  
  84.         context.getNamingResources().addService(service);  
  85.     }  
  86.     for (ServletDef servlet : servlets.values()) {  
  87.         Wrapper wrapper = context.createWrapper();  
  88.         // Description is ignored  
  89.         // Display name is ignored  
  90.         // Icons are ignored  
  91.   
  92.         // jsp-file gets passed to the JSP Servlet as an init-param  
  93.   
  94.         if (servlet.getLoadOnStartup() != null) {  
  95.             wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());  
  96.         }  
  97.         if (servlet.getEnabled() != null) {  
  98.             wrapper.setEnabled(servlet.getEnabled().booleanValue());  
  99.         }  
  100.         wrapper.setName(servlet.getServletName());  
  101.         Map<String,String> params = servlet.getParameterMap();  
  102.         for (Entry<String, String> entry : params.entrySet()) {  
  103.             wrapper.addInitParameter(entry.getKey(), entry.getValue());  
  104.         }  
  105.         wrapper.setRunAs(servlet.getRunAs());  
  106.         Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();  
  107.         for (SecurityRoleRef roleRef : roleRefs) {  
  108.             wrapper.addSecurityReference(  
  109.                     roleRef.getName(), roleRef.getLink());  
  110.         }  
  111.         wrapper.setServletClass(servlet.getServletClass());  
  112.         MultipartDef multipartdef = servlet.getMultipartDef();  
  113.         if (multipartdef != null) {  
  114.             if (multipartdef.getMaxFileSize() != null &&  
  115.                     multipartdef.getMaxRequestSize()!= null &&  
  116.                     multipartdef.getFileSizeThreshold() != null) {  
  117.                 wrapper.setMultipartConfigElement(new MultipartConfigElement(  
  118.                         multipartdef.getLocation(),  
  119.                         Long.parseLong(multipartdef.getMaxFileSize()),  
  120.                         Long.parseLong(multipartdef.getMaxRequestSize()),  
  121.                         Integer.parseInt(  
  122.                                 multipartdef.getFileSizeThreshold())));  
  123.             } else {  
  124.                 wrapper.setMultipartConfigElement(new MultipartConfigElement(  
  125.                         multipartdef.getLocation()));  
  126.             }  
  127.         }  
  128.         if (servlet.getAsyncSupported() != null) {  
  129.             wrapper.setAsyncSupported(  
  130.                     servlet.getAsyncSupported().booleanValue());  
  131.         }  
  132.         wrapper.setOverridable(servlet.isOverridable());  
  133.         context.addChild(wrapper);  
  134.     }  
  135.     for (Entry<String, String> entry : servletMappings.entrySet()) {  
  136.         context.addServletMapping(entry.getKey(), entry.getValue());  
  137.     }  
  138.     if (sessionConfig != null) {  
  139.         if (sessionConfig.getSessionTimeout() != null) {  
  140.             context.setSessionTimeout(  
  141.                     sessionConfig.getSessionTimeout().intValue());  
  142.         }  
  143.         SessionCookieConfig scc =  
  144.             context.getServletContext().getSessionCookieConfig();  
  145.         scc.setName(sessionConfig.getCookieName());  
  146.         scc.setDomain(sessionConfig.getCookieDomain());  
  147.         scc.setPath(sessionConfig.getCookiePath());  
  148.         scc.setComment(sessionConfig.getCookieComment());  
  149.         if (sessionConfig.getCookieHttpOnly() != null) {  
  150.             scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());  
  151.         }  
  152.         if (sessionConfig.getCookieSecure() != null) {  
  153.             scc.setSecure(sessionConfig.getCookieSecure().booleanValue());  
  154.         }  
  155.         if (sessionConfig.getCookieMaxAge() != null) {  
  156.             scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());  
  157.         }  
  158.         if (sessionConfig.getSessionTrackingModes().size() > 0) {  
  159.             context.getServletContext().setSessionTrackingModes(  
  160.                     sessionConfig.getSessionTrackingModes());  
  161.         }  
  162.     }  
  163.     for (Entry<String, String> entry : taglibs.entrySet()) {  
  164.         TaglibDescriptor descriptor = new ApplicationTaglibDescriptor(  
  165.                 entry.getValue(), entry.getKey());  
  166.         context.getJspConfigDescriptor().getTaglibs().add(descriptor);  
  167.     }  
  168.   
  169.     // Context doesn't use version directly  
  170.   
  171.     for (String welcomeFile : welcomeFiles) {  
  172.         /* 
  173.          * The following will result in a welcome file of "" so don't add 
  174.          * that to the context 
  175.          * <welcome-file-list> 
  176.          *   <welcome-file/> 
  177.          * </welcome-file-list> 
  178.          */  
  179.         if (welcomeFile != null && welcomeFile.length() > 0) {  
  180.             context.addWelcomeFile(welcomeFile);  
  181.         }  
  182.     }  
  183.   
  184.     // Do this last as it depends on servlets  
  185.     for (JspPropertyGroup jspPropertyGroup : jspPropertyGroups) {  
  186.         String jspServletName = context.findServletMapping("*.jsp");  
  187.         if (jspServletName == null) {  
  188.             jspServletName = "jsp";  
  189.         }  
  190.         if (context.findChild(jspServletName) != null) {  
  191.             for (String urlPattern : jspPropertyGroup.getUrlPatterns()) {  
  192.                 context.addServletMapping(urlPattern, jspServletName, true);  
  193.             }  
  194.         } else {  
  195.             if(log.isDebugEnabled()) {  
  196.                 for (String urlPattern : jspPropertyGroup.getUrlPatterns()) {  
  197.                     log.debug("Skiping " + urlPattern + " , no servlet " +  
  198.                             jspServletName);  
  199.                 }  
  200.             }  
  201.         }  
  202.     }  
  203.   
  204.     for (Entry<String, String> entry : postConstructMethods.entrySet()) {  
  205.         context.addPostConstructMethod(entry.getKey(), entry.getValue());  
  206.     }  
  207.   
  208.     for (Entry<String, String> entry : preDestroyMethods.entrySet()) {  
  209.         context.addPreDestroyMethod(entry.getKey(), entry.getValue());  
  210.     }  
  211. }  

可以看到里面对context调用了各种set、add方法,从而将web.xml中的各种配置信息与表示一个web应用的context对象关联起来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值