protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
2.默认设置的配置文件DispatcherServlet.properties,保存在属性Properties defaultStrategies中
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
3.initMultipartResolver初始化文件上传解析器,在SpringMVC上传文件时,Controller对应方法的参数必须是MultipartFile file,且要进行CommonsMultipartResolver的相关配置,这样在参数解析的时候才会对文件类型进行匹配的解析
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="15728640"/>
</bean>
3.initLocaleResolver本地化解析,没有显式设置的话,就从defaultStrategies获取默认值AcceptHeaderLocaleResolver
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
获取默认配置,使用反射获取Class文件,然后在容器中创建bean后返回。
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
String key = strategyInterface.getName();
String value = defaultStrategies.getProperty(key);
if (value != null) {
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
List<T> strategies = new ArrayList<T>(classNames.length);
for (String className : classNames) {
try {
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
Object strategy = createDefaultStrategy(context, clazz);
strategies.add((T) strategy);
}
catch (ClassNotFoundException ex) {
throw new BeanInitializationException(
"Could not find DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]", ex);
}
catch (LinkageError err) {
throw new BeanInitializationException(
"Error loading DispatcherServlet's default strategy class [" + className +
"] for interface [" + key + "]: problem with class file or dependent class", err);
}
}
return strategies;
}
else {
return new LinkedList<T>();
}
}
4.initThemeResolver主题设置,同样设置默认值FixedThemeResolver
5.initHandlerMappings请求路径映射方法的处理器配置,系统默认会有四个相关配置类RequestMappingHandlerMapping, SimpleUrlHandlerMapping,BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping,可以实现不同的路径方法映射方式
6.initHandlerAdapters初始化处理器适配设置,RequestMappingHandlerAdapter,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter
7.initHandlerExceptionResolvers初始化异常处理器,ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver,WebErrorExceptionResolver,因为我们要防止后台的错误信息展示在前端页面,并且在异常出现时可以给前端展示一些友好的信息,所以我们一般情况下都会设置自己项目的异常处理器WebErrorExceptionResolver,通过继承AbstractHandlerExceptionResolver,然后实现的doResolveException方法,最后通过下面的配置文件显式设置bean,或者直接使用注解都可以@Component,当然要确保组件扫描的路径中包含该类
<bean class="com.ph3636.WebErrorExceptionResolver"/>
8.initRequestToViewNameTranslator,默认设置为DefaultRequestToViewNameTranslator
9.initViewResolvers初始化视图设置,默认是InternalResourceViewResolver,设置获取数据后的渲染视图,如果希望前端使用jsp进行开发的话,就需要对InternalResourceViewResolver的部分属性进行配置,前后端分离并且通讯数据格式为json的话就不需要配置,默认就可以
10.initFlashMapManager,默认是SessionFlashMapManager
11.DispatcherServlet接收客户端请求开始进行处理,给request设置属性,后续会用到这些
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
}
finally {
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
12.进入处理方法doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = processedRequest != request;
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
return;
}
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
判断该请求是不是上传文件的请求,通过contentType是不是"multipart/"开头并且是POST方法
processedRequest = checkMultipart(request);
如果是上传文件,multipartResolver.resolveMultipart(request);解析请求,设置文件编码,判断文件大小是否超过限制,把文件包装成springmvc需要的文件类,最后设置标识位multipartRequestParsed
MultipartParsingResult parsingResult = parseRequest(request);
return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
13.获取请求处理器执行链HandlerExecutionChain mappedHandler = getHandler(processedRequest);,RequestMappingHandlerMapping首先根据请求路径获取对应Controller的方法HandlerMethod,这些数据在组件扫描的时候已经设置过了,获取对应路径的拦截器,当一个HandlerMapping处理成功后,也就是返回的处理器执行链不为空,后续的HandlerMapping直接略过。然后返回。当没有找到对应的处理器执行链,或者执行方法不存在时,给前端返回404错误noHandlerFound(processedRequest, response);response.sendError(HttpServletResponse.SC_NOT_FOUND);
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
chain.addInterceptors(getAdaptedInterceptors());
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
return chain;
}
14.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());获取对应请求的HandlerAdapter,
15.开始执行拦截器前置处理mappedHandler.applyPreHandle(processedRequest, response),也就是执行preHandle方法,如果执行失败就会执行afterCompletion,然后结束流程
16.执行方法处理器mv = ha.handle(processedRequest, response, mappedHandler.getHandler());方法入参解析,模型视图匹配,方法出参解析。
17.自适应默认view,applyDefaultViewName(request, mv);执行拦截器后置处理mappedHandler.applyPostHandle(processedRequest, response, mv);,拦截器的postHandle方法
18.处理结果信息processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);,当执行结果出现异常时,获取设置过得异常处理器,执行resolveException方法,
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
正常结果最后通过视图展示出来,render(mv, request, response);-》view.render(mv.getModelInternal(), request, response);清理遗留资源,结束执行。