Web容器啓動過程,主要講解Servlet和Spring容器結合的內容。html
流程圖以下:react
Web容器啓動的Root Context是有ContextLoaderListener,通常使用spring,都會在web.xml中配置這個監聽器。web
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
下面就從這裏入手,看看它是如何啓動spring容器。spring
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { public ContextLoaderListener(WebApplicationContext context) { super(context); } /** * Initialize the root web application context. */ @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } /** * Close the root web application context. */ @Override public void contextDestroyed(ServletContextEvent event) { closeWebApplicationContext(event.getServletContext()); ContextCleanupListener.cleanupAttributes(event.getServletContext()); } }
這個類繼承了ContextLoader,同時實現了ServletContextListener,從註釋上能夠看出,web應用會調用contextInitalized方法進行初始化。app
先看一下ServletContextListener.ide
public interface ServletContextListener extends EventListener { void contextInitialized(ServletContextEvent var1); void contextDestroyed(ServletContextEvent var1); }
從名字能夠看出,一個是初始化方法,另外一個是銷燬是調用的方法。post
回到上面而initWebApplicationContext方法,經過createWebApplicationContext方法獲取WebApplicationContext,調用determineContextClass方法以下:this
/** * Return the WebApplicationContext implementation class to use, either the * default XmlWebApplicationContext or a custom context class if specified. * @param servletContext current servlet context * @return the WebApplicationContext implementation class to use * @see #CONTEXT_CLASS_PARAM * @see org.springframework.web.context.support.XmlWebApplicationContext */ protected Class<?> determineContextClass(ServletContext servletContext) { String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) { try { return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); } } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); } } }
從註釋上能夠看出返回的是XmlWebApplicationContext。spa
回到initWebApplicationContext方法中,有一段code
if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> // determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } }
會調用configureAndRefreshWebApplication方法,感受是配置和刷新,進入方法。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); if (idParam != null) { wac.setId(idParam); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath())); } } wac.setServletContext(sc);
//獲取配置的參數信息 String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); if (configLocationParam != null) { wac.setConfigLocation(configLocationParam); } // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); } customizeContext(sc, wac);
//刷新上下文-->AbsreactApplicationContext.refresh() wac.refresh(); }
至此,經過wac.refresh()啓動Spring容器。