Spring源码阅读(九)—SpringMVC的初始化
2017-09-02 19:56
573 查看
Spring源码阅读(九)—SpringMVC的初始化
本文主要整理了Web应用启动时具体的初始化流程,包括Spring上下文的的初始化和SpringMVC的初始化个人主页:tuzhenyu’s page
原文地址:Spring源码阅读(九)—SpringMVC的初始化
(1) SpringMVC的初始化
SpringMVC的初始化是从Web容器如Tomcat,Jetty等启动时加载解析web.xml文件开始的,初始化只要包括两部分:ContextLoaderListener初始化
DispatcherServlet的初始化
(2) ContextLoaderListener初始化
ContextLoaderListener初始化的主要功能是将在Web应用启动时,自动装配ApplicationContext上下文环境,将Spring的IOC,AOP等功能与Web环境结合起来;每个Web应用都有一个ServletContext与之相关联作为整个Web应用的全局变量的存放地,ContextLoaderListener的核心逻辑就是初始化WebApplicationContext实例并将之放在servletContext中.使用ContextLoaderListener初始化之前需要设定Spring的配置文件地址
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param>
注册ContextLoaderListener监听器,在Web容器启动时会创建并初始化该监听器
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
ContextLoaderListener监听器实现了ServletContextListener接口对ServletContext进行监听,当ServletContext创建后会调用其contextInitialized()方法对ServletContext进行初始化;在contextInitialized()方法中会调用initWebApplicationContext()方法初始化WebApplicationContext上下文环境.
public void contextInitialized(ServletContextEvent event) { this.initWebApplicationContext(event.getServletContext()); }
initWebApplicationContext()方法调用createWebApplicationContext()方法创建上下文环境对象,调用
configureAndRefreshWebApplicationContext()方法对上下文进行初始化(refresh),并将其记录在servletContext中
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { 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!"); } else { 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 { if(this.context == null) { this.context = this.createWebApplicationContext(servletContext); } if(this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext err = (ConfigurableWebApplicationContext)this.context; if(!err.isActive()) { if(err.getParent() == null) { ApplicationContext elapsedTime = this.loadParentContext(servletContext); err.setParent(elapsedTime); } this.configureAndRefreshWebApplicationContext(err, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader err1 = Thread.currentThread().getContextClassLoader(); if(err1 == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if(err1 != null) { currentContextPerThread.put(err1, 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 elapsedTime1 = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime1 + " ms"); } return this.context; } catch (RuntimeException var8) { logger.error("Context initialization failed", var8); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8); throw var8; } catch (Error var9) { logger.error("Context initialization failed", var9); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9); throw var9; } } }
ServletContextListener创建ApplicationContext上下文环境主要包括以下几步:
在创建的过程中,会提取将要实现的WebApplicationContext接口的实现类,再根据这个实现类通过forName()反射的方式进行实例的创建;
将配置的contextConfigLocation参数(即Spring配置文件applicationContext.xml)传入ApplicationContext对象并调用refresh()方法刷新Spring容器,完成Spring容器的创建和启动;
将创建好的ApplicationContext放入ServletContext中;
(3) DispatcherServlet的初始化
DispatcherServlet实现了Servlet接口,并且在web.xml配置中load-on-startup为1则DispatcherServlet的实例化和初始化会在Web容器启动时候进行.DispatcherServlet初始化会调用init()方法public final void init() throws ServletException { if(this.logger.isDebugEnabled()) { this.logger.debug("Initializing servlet \'" + this.getServletName() + "\'"); } HttpServletBean.ServletConfigPropertyValues pvs = new HttpServletBean.ServletConfigPropertyValues(this.getServletConfig(), this.requiredProperties); if(!pvs.isEmpty()) { try { BeanWrapper ex = PropertyAccessorFactory.forBeanPropertyAccess(this); ServletContextResourceLoader resourceLoader = new ServletContextResourceLoader(this.getServletContext()); ex.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.getEnvironment())); this.initBeanWrapper(ex); ex.setPropertyValues(pvs, true); } catch (BeansException var4) { if(this.logger.isErrorEnabled()) { this.logger.error("Failed to set bean properties on servlet \'" + this.getServletName() + "\'", var4); } throw var4; } } this.initServletBean(); if(this.logger.isDebugEnabled()) { this.logger.debug("Servlet \'" + this.getServletName() + "\' configured successfully"); } }
DispatcherServlet的初始化主要是将当前的servlet类型的实例转换成BeanWrapper类型的实例,并使用Spring提供的注入功能进行相应属性的注入.同时对servletBean进行初始化.
initServletBean()方法主要是调用initWebApplication()方法对ContextLoadListener创建的ApplicationContext上下文环境进行进一步的补充.
protected final void initServletBean() throws ServletException { this.getServletContext().log("Initializing Spring FrameworkServlet \'" + this.getServletName() + "\'"); if(this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet \'" + this.getServletName() + "\': initialization started"); } long startTime = System.currentTimeMillis(); try { this.webApplicationContext = this.initWebApplicationContext(); this.initFrameworkServlet(); } catch (ServletException var5) { this.logger.error("Context initialization failed", var5); throw var5; } catch (RuntimeException var6) { this.logger.error("Context initialization failed", var6); throw var6; } if(this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet \'" + this.getServletName() + "\': initialization completed in " + elapsedTime + " ms"); } }
initWebApplicationContext()方法主要是创建或刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化
判断创建DispatcherServlet时候是否通过构造器传入了创建好的WebApplicationContext实例,默认构造器未传入
判断servletContext中是否存在已经创建好的WebApplicationContext实例,一般是由ServletContextListener创建并放入servletContext中.
如果以上两种都没有找到创建好的WebApplicationContext实例,则从头创建并进行初始化
调用initStrategies()方法对servlet功能所使用的变量进行初始化
protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext()); WebApplicationContext wac = null; if(this.webApplicationContext != null) { wac = this.webApplicationContext; if(wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext attrName = (ConfigurableWebApplicationContext)wac; if(!attrName.isActive()) { if(attrName.getParent() == null) { attrName.setParent(rootContext); } this.configureAndRefreshWebApplicationContext(attrName); } } } if(wac == null) { wac = this.findWebApplicationContext(); } if(wac == null) { wac = this.createWebApplicationContext(rootContext); } if(!this.refreshEventReceived) { this.onRefresh(wac); } if(this.publishContext) { String attrName1 = this.getServletContextAttributeName(); this.getServletContext().setAttribute(attrName1, wac); if(this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet \'" + this.getServletName() + "\' as ServletContext attribute with name [" + attrName1 + "]"); } } return wac; }
调用initStrategies()方法对servlet功能所使用的变量进行初始化,这个函数才是SpringMVC核心逻辑的初始化所在
protected void initStrategies(ApplicationContext context) { this.initMultipartResolver(context); this.initLocaleResolver(context); this.initThemeResolver(context); this.initHandlerMappings(context); this.initHandlerAdapters(context); this.initHandlerExceptionResolvers(context); this.initRequestToViewNameTranslator(context); this.initViewResolvers(context); this.initFlashMapManager(context); }
(4) 结论
SpringMVC的初始化主要包括两部分:ServletContextListener监听器初始化WebApplicationContext将Spring与Web应用结合起来,DispatcherServlet初始化判断是否WebApplicationContext已经被创建如果没有则重新创建,如果有则进行相应的属性注入,同时也会对servlet功能所使用的变量进行初始化.相关文章推荐
- SpringMVC深度探险(1,2,3,4)Spring源码阅读:Spring MVC 初始化 - 螺 丝 钉 / DispatcherServlet的初始化主线
- Spring源码阅读之IoC容器初始化2 -- BeanDefinition载入与解析
- 初始化IoC容器(Spring源码阅读)-我们到底能走多远系列(31)
- Spring之SpringMVC(源码)初始化DispatcherServlet策略配置
- Spring源码阅读之IoC容器初始化3 -- BeanDefinition在IoC容器中的注册
- Spring 源码阅读五 IOC容器初始化之bean定义载入
- Spring源码阅读(一):IOC容器的初始化
- 初始化IoC容器(Spring源码阅读)
- SpringMVC启动与初始化源码阅读
- Spring 源码阅读(二)——Spring的初始化以及资源加载
- Spring 源码阅读 BeanFactory(三) 对象的初始化 singleton 草稿
- Spring源码阅读(八)—SpringMVC基础Servlet
- Spring源码阅读(二)—IOC容器初始化
- Spring之SpringMVC(源码)启动初始化过程分析
- Spring源码阅读之IoC容器初始化1 -- Resource定位
- spring源码学习笔记-初始化(三)-BeanFactory
- Spring 源码阅读笔记(一)
- EventBus源码阅读(19)-EventBus初始化
- Spring源码阅读3-bean获取-下
- springmvc mybatis 整合 框架源码 bootstrap html5 mysql oracle spring