// org.springframework.web.context.ContextLoaderListener#contextInitialized publicvoidcontextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { // web.xml中存在多次ContextLoader定义 thrownewIllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); }
servletContext.log("Initializing Spring root WebApplicationContext"); Loglogger= LogFactory.getLog(ContextLoader.class); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } longstartTime= System.currentTimeMillis();
try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { // 初始化context,第一次执行的时候获取到一个root webApplicationcontext this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContextcwac= (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. ApplicationContextparent= loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } // 将创建的context对象记录在servletContext中,创建并且准备好了spring容器 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
protectedvoidconfigureAndRefreshWebApplicationContext(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 StringidParam= 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())); } }
// 设置环境变量 // 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 ConfigurableEnvironmentenv= wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); }
// 启动容器前设置上下文信息 customizeContext(sc, wac); // 启动 Spring 容器 wac.refresh(); }
if (logger.isDebugEnabled()) { Stringvalue=this.enableLoggingRequestDetails ? "shown which may lead to unsafe logging of potentially sensitive data" : "masked to prevent unsafe logging of potentially sensitive data"; logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails + "': request parameters and headers will be " + value); }
if (logger.isInfoEnabled()) { logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms"); } }
// 如果构造方法中已经传入webApplicationContext属性,则直接使用 // 此方式主要用于servlet3.0之后的环境,也就是说可以通过ServletContext.addServlet的方法注册servlet,此时就可以在创建FrameworkServlet和 // 其子类的时候通过构造方法传递已经准备好的webApplicationContext if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; // 如果是ConfigurationWebApplicationContext类型,并且未激活,则进行初始化 if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContextcwac= (ConfigurableWebApplicationContext) wac; // 未激活 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 -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } // 配置和刷新上下文环境 configureAndRefreshWebApplicationContext(cwac); } } } // 从servletContext获取对应的webApplicationContext对象 // 此方式需要在配置Servlet的时候将servletContext中的webApplicationContext的name配置到contextAttribute属性就可以 /* <servlet> <servlet-name>mvc-test</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--SpringMVC配置文件--> <init-param> <param-name>contextAttribute</param-name> <param-value>val</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> */ if (wac == null) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id wac = findWebApplicationContext(); } // 当前面两种方式都无效的情况下会创建一个webApplicationContext对象,一般情况下都是使用这样的方式 if (wac == null) { // No context instance is defined for this servlet -> create a local one wac = createWebApplicationContext(rootContext); }
// 将contextRefreshedEvent事件没有触发时调用此方法,模板方法,可以在子类重写 if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. synchronized (this.onRefreshMonitor) { onRefresh(wac); } }
// 将applicationContext设置到servletContext中 if (this.publishContext) { // Publish the context as a servlet context attribute. StringattrName= getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); }
protectedvoidconfigureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { // 如果wac使用了默认编号,则重新设置id属性 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 // 使用contextId属性 if (this.contextId != null) { wac.setId(this.contextId); } // 自动生成 else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName()); } }
// 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 // 获取环境对象并且添加相关的属性 ConfigurableEnvironmentenv= wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); }