昨天講到DispatcherServlet因為繼承了FrameworkServlet、HttpServletBean、HttpServlet,是以可以通過Servlet的API對請求進行一些處理與響應。
DispatcherServlet的初始化在ContextLoaderListener完成對根上下文的初始化之後才會執行。
具體的初始化時間取決于web.xml中servlet關于load-on-startup的配置。
當load-on-startup為負數或者沒有配置時,在第一次request請求時加載;
當load-on-startup不為負數時,代表DispatcherServlet在ContextLoaderListener完成根上下文的初始化之後即加載。
下面來看DispatcherServlet具體的初始化源碼:
HttpServletBean重寫了其父類HttpServlet的init方法:
public final void init() throws ServletException {
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
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) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
initServletBean();
}
HttpServletBean的init方法,讀取Servlet的初始化參數,然後調用initServletBean來初始化Servlet的Bean對象。
這個initServletBean是一個鈎子方法,由子類去實作。
在這裡調用到子類
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
if (logger.isInfoEnabled()) {
logger.info("Initializing Servlet '" + getServletName() + "'");
}
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
if (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";
logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
"': request parameters and headers will be " + value);
}
if (logger.isInfoEnabled()) {
logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
}
}
initServletBean中實作了DispatcherServlet中上下文的實作,設定上下文的根上下文,并使ServletContext持有這個DispatcherServlet上下文。
initWebApplicationContext中的onRefresh()方式用來在初始化spring mvc需要的bean
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);
//這裡配置path 與 handler ,也是什麼請求,走什麼樣的處理器
//而處理器,是一系列攔截器+Controller組成
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}