二、接下来分析一下DispatcherServlet这个前端控制器的启动和初始化的整个过程
通过前面分析已经知道了DispatcherServlet这个前端控制器是一个Servlet了,所以生命周期和普通的Servlet是差不多的,在一个Servlet初始化的时候都会调用该Servlet的init()方法。下面这个是DispatcherSerlvet父类HttpServletBean中的init方法。
我们发现这里会调用initServletBean()方法进行具体的初始化,而该类这个方法的具体实现这是其子类FrameworkServlet。主要逻辑就是初始化上下文。
protected final void initServletBean() throws ServletException {
this.getServletContext().log("Initializing Spring " + this.getClass().getSimpleName() + " \'" + this.getServletName() + "\'");
if(this.logger.isInfoEnabled()) {
this.logger.info("Initializing Servlet \'" + this.getServletName() + "\'");
}
long startTime = System.currentTimeMillis();
try {
/**
这里初始化上下文
**/
this.webApplicationContext = this.initWebApplicationContext();
this.initFrameworkServlet();
} catch (RuntimeException | ServletException var4) {
this.logger.error("Context initialization failed", var4);
throw var4;
}
if(this.logger.isDebugEnabled()) {
String value = this.enableLoggingRequestDetails?"shown which may lead to unsafe logging of potentially sensitive data":"masked to prevent unsafe logging of potentially sensitive data";
this.logger.debug("enableLoggingRequestDetails=\'" + this.enableLoggingRequestDetails + "\': request parameters and headers will be " + value);
}
if(this.logger.isInfoEnabled()) {
this.logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
继续跟进initWebApplicationContext这个方法
protected WebApplicationContext initWebApplicationContext() {
/**
若webApplicationContext不为空的时候从SerlvetContext去出根上下文作为它的双亲上下文
**/
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);
}
//这里通过调用子类DispatcherServlet实现的onRefresh方法
if(!this.refreshEventReceived) {
this.onRefresh(wac);
}
//把当前建立好的上下文存到ServletContext里面去
if(this.publishContext) {
String attrName1 = this.getServletContextAttributeName();
this.getServletContext().setAttribute(attrName1, wac);
}
return wac;
}
继续跟进这个onRefresh方法,发现是一个模板方法,其具体实现子类则是DispatcherServlet。
跳转到DispatcherServlet中查看该方法,发现里面又调用了initStrategies这个方法
这时我们就大致了解了,这个DispatcherServlet初始化的过程了,首先DispatcherServlet持有者一个以自己的Servlet名字命名的Ioc容器,也就是我们看到的WebApplicationContext对象,这个Ioc容器建立起来后,与Web容器相关的各种配置加载也都完成了。并且这个初始化的入口就是由最初的HttpServletBean的init方法触发的,因为这个HttpServletBean是HttpServlet的子类,接下来HttpServletBean的子类FrameworkServlet对Ioc容器进行了初始化操作,并且利用onRefresh方法回调了DispatcherServlet中的initStrategies方法,在这个方法里启动了整个SpringMVC框架了,我们继续往下面跟进看看。
//该属性默认为true
private boolean detectAllHandlerMappings = true;
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//这里面的逻辑是从导入所有的HandlerMappingBean,这些Bean有可能存在与双亲容器中,也可能在DispathcerServlet持有的容器的,这里detectAllHandlerMappings默认为true,默认从所有容器中导入
if(this.detectAllHandlerMappings) {
Map hm = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if(!hm.isEmpty()) {
this.handlerMappings = new ArrayList(hm.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
//否则通过直接通过名字从当前的IOC容器中通过getBean方法获取handlerMapping
try {
HandlerMapping hm1 = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm1);
} catch (NoSuchBeanDefinitionException var3) {
;
}
}
//如果还是没有找到hadlerMapping就需要设定默认的handlerMappings了
if(this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if(this.logger.isTraceEnabled()) {
this.logger.trace("No HandlerMappings declared for servlet \'" + this.getServletName() + "\': using default strategies from DispatcherServlet.properties");
}
}
}
下面是用debugger看看它究竟获取了那些handlerMapping,如下:7个handlerMapping
除了这个初始化handlerMapping的initHandlerMapping方法,当然还初始化了很多东西,如支持国际化的LocalResolver以及视图生成的ViewResolver等的初始化过程,其余的有兴趣自己跟着看一下,这里就不细跟了。到这里我们就知道了整个DispatcherServlet的初始化的大体流程了。