DispatcherServlet继承关系
初始化过程分析
* 调用HttpServletBean的init方法(内部的initServletBean方法是空方法,交由FrameworkServlet实现)
DispatcherServlet中没有定义init方法,是从httpservlet中继承过来的,在HttpServletBean中重写
HttpServletBean中init方法
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
throw ex;
}
// Let subclasses do whatever initialization they like.
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
1. 先看下第一行代码,创建一个PropertyValues
将servletconfig获取到的servlet的初始化参数和值,创建propertyvalue对象,添加到propertyValueList中
public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
throws ServletException {
Set<String> missingProps = (requiredProperties != null && !requiredProperties.isEmpty()) ?
new HashSet<String>(requiredProperties) : null;
Enumeration<String> en = config.getInitParameterNames();
while (en.hasMoreElements()) {
String property = en.nextElement();
Object value = config.getInitParameter(property);
addPropertyValue(new PropertyValue(property, value));
if (missingProps != null) {
missingProps.remove(property);
}
}
// Fail if we are still missing properties.
if (missingProps != null && missingProps.size() > 0) {
throw new ServletException(
"Initialization from ServletConfig for servlet '" + config.getServletName() +
"' failed; the following required properties were missing: " +
StringUtils.collectionToDelimitedString(missingProps, ", "));
}
}
}
2. 给当前的对象生成BeanWrapper对象(这个BeanWrapper类是一个不通过创建对象,通过创建PropertyValue设置对象的属性值) ,关于BeanWrapper的介绍
3. 调用BeanWrapper对象的setPropertyValues,设置DispatcherServlet的初始化参数。
4. 调用initServletBean方法,在HTTPServletBean中是空方法,由DispatcherServlet的上一级父类FrameworkServlet实现
protected void initServletBean() throws ServletException {
}
FrameworkServlet的initServletBean方法
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
创建webApplicationContext(这个接口继承自ApplicationContext)并设置到ServletContext中,这样将web容器和Spring上下文关联起来了。
具体细节
protected WebApplicationContext initWebApplicationContext() {
//获取根上下文
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
//DispatcherServlet的构造器中如果webApplicationContext参数不为空,调用
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (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);
}
//设置webApplicationContext
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
//根据contextAttribute属性来获取webapplicationContext,一般设置DispatcherServlet的属性时候不设置,这里就不执行
wac = findWebApplicationContext();
}
if (wac == null) {
//DispatcherServlet初始化最终调用的方法,创建上下文,并配置上下文的父上下文
wac = createWebApplicationContext(rootContext);
}
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.
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);//将创建的容器上下文设置到ServletContext中
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
这里的根上下文是web.xml中配置的ContextLoaderListener监听器中根据contextConfigLocation路径生成的上下文。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springConfig/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
onRefresh方法会在DispatcherServlet中重写,用于初始化springMVC的组件
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
总结
1. HttpServletBean
将web.xml中配置的servlet参数设置到DispatcherServlet的属性上
2. FrameworkServlet
创建WebApplicationContext并设置到ServletContext上,将SpringMVC的上下文和servlet容器关联,
WebApplicationContext有个父类的上下文,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。
3.DispatcherServlet
初始化springMVC依赖的各个组件
参考: http://www.cnblogs.com/fangjian0423/p/springMVC-dispatcherServlet.html