您的位置:首页 > 编程语言 > Java开发

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功能所使用的变量进行初始化.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: