继承体系结构如下所示:
HttpServletBean继承HttpServlet,因此在Web容器启动时将调用它的init方法,该初始化方法的主要作用。
- 将Servlet初始化参数(init-param)设置到该组件上(如contextAttribute、contextClass、namespace、contextConfigLocation),通过BeanWrapper简化设值过程,方便后续使用;
- 提供给子类初始化扩展点,initServletBean(),该方法由FrameworkServlet覆盖。
public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware {
@Override
public final void init() throws ServletException {
// 省略部分代码
// 1、如下代码的作用是将Servlet初始化参数设置到该组件上
// 如 contextAttribute、contextClass、namespace、contextConfigLocation
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 , this.environment));
initBeanWrapper(bw);
bw.setPropertyValues(pvs , true);
} catch (BeansException ex) {
// ...... 省略其他代码
}
// 2、提供给子类初始化的扩展点,该方法由FrameworkServlet覆盖
initServletBean();
if(logger.isDebugEnabled()) {
logger.debug("servlet '" + getServletName() + "' configured successfully" );
}
}
// ... ... 省略其他代码
}
FrameworkServlet继承HttpServletBean,通过initServletBean()进行Web上下文初始化,该方法主要覆盖一下两件事情:
- 初始化web上下文;
- 提供给子类初始化扩展点;
public abstract class FrameworkServlet extends HttpServletBean {
@Override
protected final void initServletBean() throws ServletException {
// 省略部分代码
try {
// 1、初始化Web上下文
this.webApplicationContext = initWebApplicationContext();
// 2、提供给子类初始化的扩展点
initFrameworkServlet();
}
// 省略部分代码
}
}
protected WebApplicationContext initWebApplicationContext() {
// ROOT上下文(ContextLoaderListener加载的)
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// 1、在创建该Servlet注入的上下文
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if(!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// 2、查找已经绑定的上下文
wac = findWebApplicationContext();
}
if (wac == null) {
// 3、如果没有找到相应的上下文,并指定父亲为ContextLoaderListener
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// 4、刷新上下文(执行一些初始化)
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName()
getServletContext().setAttribute(attrName , wac);
// 省略部分代码
}
return wac;
}
从initWebApplicationContext()方法可以看出,基本上如果ContextLoaderListener加载了上下文将作为根上下文(DispatcherServlet的父容器)。
最后调用了onRefresh()方法执行容器的一些初始化,这个方法由子类实现,来进行扩展。
DispatcherServlet继承FrameworkServlet,并实现了onRefresh()方法提供一些前端控制器相关的配置:
public class DispatcherServlet extends FrameworkServlet {
// 实现子类的onRefresh()方法,该方法委托为initStrategies()方法。
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
// 初始化默认的Spring Web MVC框架使用的策略(如HandlerMapping)
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
从如上代码可以看出,DispatcherServlet启动时会进行我们需要的Web层Bean的配置,如HandlerMapping、HandlerAdapter等,而且如果我们没有配置,还会给我们提供默认的配置。
从如上代码我们可以看出,整个DispatcherServlet初始化的过程和做了些什么事情,具体主要做了如下两件事情:
- 初始化Spring Web MVC 使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);
- 初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。
服务器启动时的日志分析(此处加了ContextLoaderListener从而启动ROOT上下文容器):
从如上日志我们也可以看出,DispatcherServlet会进行一些默认的配置。