Spring Mvc研究
2017-10-18 本文已影响0人
IceBins
-
首先在web.xml中配置了listener, 并配置了参数contextConfigurationLocation,指定context的配置文件路径, 默认配置的listener为
org.springframework.web.context.ContextLoaderListener
,该类继承自ContextLoader类 -
ServletContext启动之后会调用listener的contextInitialized函数,查看下函数
this.initWebApplicationContext(event.getServletContext());
最终会调用ContextLoader的initWebApplicationContext函数
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 cwac = (ConfigurableWebApplicationContext)this.context;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
ApplicationContext parent = this.loadParentContext(servletContext);
cwac.setParent(parent);
}
this.configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.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 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;
}
}
在initWebApplicationContext函数中主要是做了三件事:创建webApplicationContext, 然后将context设置到servletContext(名称为WebApplicationContext.ROOT)中, 最后映射类加载器和创建的实例到currentContextPerThread中。
-
接下来是DispatchServlet的处理,
3.1 按照《源码深度解析》一书中所说, servlet有三个阶段:- 初始化阶段
- 加载Servlet类;
- 创建ServletConfig对象, 包含了servlet的初始化配置信息
- 创建servlet对象, 并调用其init函数初始化
- 运行阶段
- servlet容器创建servletRequest对象和servletResponse对象
- 调用service函数处理并返回结果
- 销毁阶段
- servlet容器首先调用servlet对象的destroy函数, 然后销毁servlet对象, 销毁servletConfig对象
3.2. DispatchServlet -> init(将servlet对象转换成BeanWrapper对象,便于spring容易管理以及参数注入)
- 加载参数, 即servlet配置中的init-param,包装类为ServletConfigPropertyValues
- 把当前的servlet包装成BeanWrapper
- 注册resourceLoader
- initBeanWrapper
- initServletBean
该函数在父类FrameServlet中实现, 完成两件事:initWebApplicationContext() 和 initFrameworkServlet(留给子类实现)- initWebApplicationContext函数如下:
- 初始化阶段
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
this.configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
wac = this.findWebApplicationContext();
}
if (wac == null) {
wac = this.createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
this.onRefresh(wac);
}
if (this.publishContext) {
String attrName = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + this.getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
- 首先从servletContext中尝试获得WebApplicationContext,这个是由contextlistener设置的,若不为空执行2, 否则执行3
- configureAndRefreshWebApplicationContext
- 尝试设置servletContext, servletConfig, namespace等参数
- 根据profile选择不同的参数源
- applyInitializer
- 最终会执行refresh函数, 最终都会执行AbstractApplicatonContext中提供的refresh函数, 完成bean容器的初始化
- 若context为null, 可能的原因是设置的key不对, 则尝试重新从servletContext中获取
- 若context仍然为null, 则尝试重新创建WebApplicationContext, 设置一些常用参数如contextConfigurationLocation等, 并执行configureAndRefreshWebApplicationContext.
- 执行onRefresh函数, 在FrameworkServlet中会触发onRefresh函数, 最终会调用DispatchServlet的onRefresh函数.
- initMultipartResolver
- initLocaleResolver
- initThemeResolver
- initHandlerMappings
- HandlerMapping是根据request获得HandlerExecutionChain, 即执行链
- 默认情况下(detectAllHandlerMappings)会加载所有的实现HandlerMapping接口的类, 并按照优先级排序。
- initHandlerAdapters
- initHandlerExceptionResolvers
- initRequestToViewNameTranslator
- initViewResolvers
- initFlashMapManager