SpringMVC原始碼剖析(一) DispatcherServlet
一、DispatcherServlet構造方法
DispatcherServlet有兩個構造方法,一個無引數的構造方法和一個WebApplicationContext引數的構造方法,如下程式碼:
public DispatcherServlet() {
}
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
}
其中重點看有引數的構造方法,其主要是呼叫其父類的構造方法,DispatcherServlet是繼承父類FrameworkServlet,我們看下FrameworkServlet的構造方法,其程式碼如下:
public FrameworkServlet(WebApplicationContext webApplicationContext) { this.contextClass = DEFAULT_CONTEXT_CLASS; this.publishContext = true; this.publishEvents = true; this.threadContextInheritable = false; this.dispatchOptionsRequest = false; this.dispatchTraceRequest = false; this.webApplicationContextInjected = false; this.refreshEventReceived = false; this.contextInitializers = new ArrayList(); this.webApplicationContext = webApplicationContext; }
其中DEFAULT_CONTEXT_CLASS是XmlWebApplicationContext的類,主要是對其中一些屬性進行賦值。
二、屬性設定
DispatcherServlet通過set方法設定了一些屬性,這些屬性的預設值都為true,如下:
1、detectAllHandlerMappings
2、detectAllHandlerAdapters
3、detectAllHandlerExceptionResolvers
4、detectAllViewResolvers
5、throwExceptionInfoHandlerFound
6、cleanupAfterInclude
三、初始化
DispatcherServlet中有一個onRefresh方法,其主要呼叫的是initStrategies(context)方法
再看一下initStrategies(context)方法的原始碼
protected void initStrategies(ApplicationContext context) {
this.initMultipartResolver(context);
this.initLocaleResolver(context);
this.initThemeResolver(context);
this.initHandlerMappings(context);
this.initHandlerAdapters(context);
this.initHandlerExceptionResolvers(context);
this.initRequestToViewNameTranslator(context);
this.initViewResolvers(context);
this.initFlashMapManager(context);
}
主要做的是一些檔案上傳解析器,HandlerMappings等的一些初始化,會呼叫這些元件的私有初始化方法進行初始化。
例如檔案上傳解析器初始化initMultipartResolver方法
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
} catch (NoSuchBeanDefinitionException var3) {
this.multipartResolver = null;
if (this.logger.isDebugEnabled()) {
this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
}
}
}
首先從context中通過getBean方法獲取一個multipartResolver物件,並賦值到DispatcherServlet中的mutipartResolver屬性中。如果出現異常,會將mutipartResolver屬性設為空,並且列印日誌。
方法initLocaleResolver和initThemeResolver和其類似。
看一下方法initHandlerMappings(ApplicationContext context)
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList(matchingBeans.values());
OrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException var3) {
;
}
}
if (this.handlerMappings == null) {
this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
if (this.logger.isDebugEnabled()) {
this.logger.debug("No HandlerMappings found in servlet '" + this.getServletName() + "': using default");
}
}
}
首先將handlerMappings設定為空,建立了一個Map<String,HandlerMapping>,String和HandlerMapping的key-value的map,通過BeanFactoryUtils的方法beansOfTypeIncludingAncestors,這個方法的作用是根據型別尋找bean,找出所有匹配型別的beanName,取出匹配bean的值,放入handlerMappings的ArrayList陣列中,並且進行排序,這個排序底層呼叫的是Collections.sort()的方法,傳入了一個OrderComparator的比較器。
如果沒有找到handlerMapping,會使用一個預設的BeanNameUrlHandlerMapping,確保有至少有一個HandlerMapping
四、get方法
DispatcherServlet定義了獲取這些屬性的get方法
五、預設策略方法
建立一個預設的策略,其預設實現使用AutoworeCapableBeanFactory的createBean方法
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
return context.getAutowireCapableBeanFactory().createBean(clazz);
}