javascript
SpringMVC Root WebApplicationContext启动流程
傳統(tǒng)的SpringMVC項(xiàng)目中,需要在web.xml中配置Contextlistener。ContextLoaderListener是負(fù)責(zé)引導(dǎo)啟動(dòng)和關(guān)閉Spring的Root上下文的監(jiān)聽(tīng)器。主要將處理委托給ContextLoader和ContextCleanupListener。
類的繼承關(guān)系。
ContextLoaderListener實(shí)現(xiàn)了ServletContextListener接口。該接口主要定義了兩個(gè)行為:監(jiān)聽(tīng)上下文創(chuàng)建(contextInitialized)和監(jiān)聽(tīng)上下文銷(xiāo)毀(contextDestroyed)。
ContextLoaderListener只是將方法的處理委托給ContextLoader。
ContextLoader的initWebApplicationContext方法負(fù)責(zé)創(chuàng)建root web application context。
//初始化root web application context public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {//校驗(yàn)是否已經(jīng)存在root application,if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {throw new IllegalStateException("Cannot initialize context because there is already a root application context present - " +"check whether you have multiple ContextLoader* definitions in your web.xml!");}Log logger = LogFactory.getLog(ContextLoader.class);servletContext.log("Initializing Spring root WebApplicationContext");if (logger.isInfoEnabled()) {logger.info("Root WebApplicationContext: initialization started");}long startTime = System.currentTimeMillis();try {// Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown.//創(chuàng)建WebApplicationContext,并保存到變量中,等關(guān)閉時(shí)使用if (this.context == null) {this.context = createWebApplicationContext(servletContext);}//如果是ConfigurableWebApplicationContext,則配置上下文并刷新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, etcif (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);}}//在ServletContext中設(shè)置屬性,表明已經(jīng)配置了root web application contextservletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);ClassLoader ccl = Thread.currentThread().getContextClassLoader();if (ccl == ContextLoader.class.getClassLoader()) {currentContext = this.context;}else if (ccl != null) {currentContextPerThread.put(ccl, this.context);}if (logger.isDebugEnabled()) {logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");}if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime;logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");}return this.context;}catch (RuntimeException ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);throw ex;}catch (Error err) {logger.error("Context initialization failed", err);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);throw err;}}該方法主要分為四步:
這四步具體分析如下:
1.校驗(yàn)
校驗(yàn)的過(guò)程比較簡(jiǎn)單,主要是判斷Servlet Context是否已經(jīng)綁定過(guò)WebApplicationContext
2.創(chuàng)建對(duì)象
createWebApplicationContext()方法負(fù)責(zé)創(chuàng)建WebApplicationContext對(duì)象,主要過(guò)程是確定WebApplicationContext類,并實(shí)例化:
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {//查找WebApplicationContext的類Class<?> contextClass = determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");}//實(shí)例化對(duì)象return(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}決定WebApplicationContext類的主要策略是先判斷ServletContext是否配置了contextClass屬性,如果是,則用該屬性指定的類作為WebApplicationContext類,否則則是否默認(rèn)策略。默認(rèn)策略是根絕classpath下的ContextLoader.properties中配置的類作為WebApplicatioNCOntext類:
protected Class<?> determineContextClass(ServletContext servletContext) {//優(yōu)先根據(jù)servletContext配置的contextClass屬性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);}}//在通過(guò)classpath下的`ContextLoader.properties`文件制定的類作為WebApplicationContext類//默認(rèn)是XmlWebApplicationContextelse {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);}}}配置與刷新
創(chuàng)建WebApplicationContext對(duì)象后,ContextLoader會(huì)判斷是否是ConfigurableWebApplicationContext。
ConfigurableWebApplicationContext拓展了WebApplicationContext的能力。其不僅擴(kuò)展了自身方法,還繼承了ConfigurableApplicationContext接口。
配置與刷新的步驟也正是利用了這些接口提供的能力。
//配置并刷新上下文protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {//設(shè)置IDif (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 informationString 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()));}}//WebApplicationContext綁定Servlet Contextwac.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 #refreshConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}//自定義上下文初始過(guò)程,留給用戶的拓展機(jī)制customizeContext(sc, wac);//刷新上下文,加載beanwac.refresh();}創(chuàng)建流程圖如下:
轉(zhuǎn)載于:https://www.cnblogs.com/insaneXs/p/11115862.html
總結(jié)
以上是生活随笔為你收集整理的SpringMVC Root WebApplicationContext启动流程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: nex双屏防水吗(2020年索尼nex7
- 下一篇: 如何卸载显卡驱动重新安装 Win10卸载