1.springmvc中DispatcherServlet继承体系
2.概述
1)初始化各种组件
主要组件有
- MultipartResolver:文件上传处理
- LocaleResolver:多语言支持
- ThemeResolver:切换主题
- HandlerMappings:处理器,这个请求的处理器
- HandlerAdapters:处理器适配器,调用处理器
- HandlerExceptionResolvers:全局异常处理
- RequestToViewNameTranslator:如果没有指定的视图,会将http请求转为视图
- ViewResolvers:视图解析,逻辑上的视图名称解析为一个真正的视图
- FlashMapManager:重定向管理
2)http中央调度处理程序,实际请求分发到JavaBean,通常转发到controller中@RequestMapping路径的方法,也可以是实现controller接口的方法等
3.DispatcherServlet整个代码用工具翻译后的
springmvc源码-DispatcherServlet_LouD_dm的博客-CSDN博客_springmvc 源码
4.初始化各种组件
1)首先在DispatcherServlet实现了FrameworkServlet的onRefresh方法,在onRefresh方法初始化各种组件
/**
* 这个实现调用{@link#initStrategies}。
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* 初始化此servlet使用的策略对象。
* <p>可以在子类中重写,以初始化其他策略对象。
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
2)detectAllHandlerMappings默认为true,会检测spring容器中所有HandlerMapping类型的bean,如果为空,获取配置文件下的默认策略
/**
* 初始化此类使用的HandlerMappings。
* *<p>如果BeanFactory中没有为此命名空间定义HandlerMapping bean,
* *我们默认为BeanNameUrlHandlerMapping。
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// 在ApplicationContext中查找所有HandlerMappings,包括祖先上下文。
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
//我们保持handler映射的有序性。
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
} else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
} catch (NoSuchBeanDefinitionException ex) {
//忽略,我们稍后将添加默认HandlerMapping。
}
}
// 通过注册,确保我们至少有一个HandlerMapping
// 如果找不到其他映射,则为默认HandlerMapping。
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
DispatcherServlet中有一个static块,加载对应的DispatcherServlet.properties的默认策略
private static final Properties defaultStrategies;
static {
//从属性文件加载默认策略实现。
//这是目前严格的内部,并不意味着定制
//应用程序开发人员。
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
DispatcherServlet.properties文件内容
# DispatcherServlet 的策略接口的默认实现类。
# 当在 DispatcherServlet 上下文中找不到匹配的 bean 时用作回退。
# 不打算由应用程序开发人员定制。
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.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
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
getDefaultStrategies方法从配置文件中获取默认的策略,反射实例化并返回
/**
*为给定的策略接口创建默认策略对象列表。
* * <p>默认实现使用“DispatcherServlet”。属性”文件(在相同的
* *包为DispatcherServlet类)来确定类名。它实例化
* *策略通过上下文的BeanFactory对象。
*
* @param context the current WebApplicationContext
* @param strategyInterface the strategy interface
* @return the List of corresponding strategy objects
*/
@SuppressWarnings("unchecked")
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<>(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(
"Unresolvable class definition for DispatcherServlet's default strategy class [" +
className + "] for interface [" + key + "]", err);
}
}
return strategies;
} else {
return new LinkedList<>();
}
}
5.请求实际分发
1)DispatcherServlet实现了FrameworkServlet的doService的方法
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// 如果包含,请保留请求属性的快照,
//以便能够在包含之后恢复原始属性。
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 使框架对象可用于处理程序并查看对象。
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());
if (this.flashMapManager != null) {
//查询与当前请求关联的先前请求的FlashMap
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()) {
//如果包含,则还原原始属性快照.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
主要是doDispatch方法,实际分发请求
/**
* 处理向处理程序的实际分派。
* <p>该处理程序将通过依次应用servlet的HandlerMappings获得。
* HandlerAdapter将通过查询Servlet的已安装HandlerAdapters获得。
* 查找第一个支持处理程序类的对象。
* <p>所有HTTP方法均由该方法处理。由HandlerAdapters或处理程序决定
* 自己决定可接受的方法。
*
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
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);
// 确定当前请求的处理程序。并封装为一个HandlerExecutionChain类
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//没有请求处理
noHandlerFound(processedRequest, response);
return;
}
// 确定当前请求的处理程序适配器.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理最后修改的标头(如果处理程序支持).
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
//浏览器缓存,校验如果资源在lastModified时间内没有更改,并且是get或head请求,直接返回
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用拦截器处理前的方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际调用处理程序。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//视图名称转换
applyDefaultViewName(processedRequest, mv);
//调用拦截器处理后的方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
// 从4.3开始,我们也在处理处理程序方法抛出的错误,
使它们可用于@ExceptionHandler方法和其他场景。
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
} catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// 而不是在完工后
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
// 清理多部分请求使用的所有资源。
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
1.doDispatch方法中获取异步管理类WebAsyncManager,在finally中校验如果是异步请求执行异步处理
2.校验是否是文件上传请求,如果是将给定的HTTP请求解析为多部分文件和参数,并且将请求转换为MultipartHttpServletRequest
/**
* 将请求转换为多部分请求,并使多部分解析器可用。
* <p>如果未设置多部分解析器,则只需使用现有请求。
*
* @param request current HTTP request
* @return the processed request (multipart wrapper if necessary)
* @see MultipartResolver#resolveMultipart
*/
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
}
} else if (hasMultipartException(request)) {
logger.debug("Multipart resolution previously failed for current request - " +
"skipping re-resolution for undisturbed error rendering");
} else {
try {
return this.multipartResolver.resolveMultipart(request);
} catch (MultipartException ex) {
if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
logger.debug("Multipart resolution failed for error dispatch", ex);
// 使用下面的常规请求句柄保持处理错误的分派
} else {
throw ex;
}
}
}
}
// 如果之前未返回:返回原始请求。
return request;
}
3.遍历当前的所有处理器,根据当前请求获取,获取到和拦截器封装为一个HandlerExecutionChain并返回,否则返回为空,在外边如果没有对应的处理器返回错误的信息
如果没有配置,在前面DispatcherServlet.properties中默认配置有BeanNameUrlHandlerMapping,RequestMappingHandlerMapping和RouterFunctionMapping
BeanNameUrlHandlerMapping初始化和getHandler方法处理逻辑
1)AbstractHandlerMapping
springmvc组件HandleMapping源码分析-AbstractHandlerMapping_LouD_dm的博客-CSDN博客
2)AbstractUrlHandlerMapping
springmvc组件HandleMapping源码分析-AbstractUrlHandlerMapping_LouD_dm的博客-CSDN博客
3)AbstractDetectingUrlHandlerMapping
springmvc组件HandleMapping源码分析-AbstractDetectingUrlHandlerMapping_LouD_dm的博客-CSDN博客
4)BeanNameUrlHandlerMapping
springmvc组件HandleMapping源码分析-BeanNameUrlHandlerMapping_LouD_dm的博客-CSDN博客
RequestMappingHandlerMapping初始化和getHandler方法处理逻辑
1)AbstractHandlerMapping
springmvc组件HandleMapping源码分析-AbstractHandlerMapping_LouD_dm的博客-CSDN博客
2)AbstractHandlerMethodMapping
springmvc组件HandleMapping源码分析-AbstractHandlerMethodMapping_LouD_dm的博客-CSDN博客
3)RequestMappingHandlerMapping
springmvc组件HandleMapping源码分析-RequestMappingHandlerMapping_LouD_dm的博客-CSDN博客
/**
* 返回此请求的HandlerExecutionChain。
* <p>按顺序尝试所有处理程序映射.
*
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
4.根据处理器获取处理器适配器,也就是这个处理器对应的执行者
RequestMappingHandlerAdapter处理HandleMethed类型的处理器
1.AbstractHandlerMethodAdapter
springmvc组件HandlerAdapter源码分析-AbstractHandlerMethodAdapter_LouD_dm的博客-CSDN博客
2.RequestMappingHandlerAdapter
springmvc组件HandlerAdapter源码分析-RequestMappingHandlerAdapter_LouD_dm的博客-CSDN博客
/**
* 返回此处理程序对象的HandlerAdapter。
*
* @param handler 处理程序对象以查找适配器
* @throws ServletException 如果找不到处理程序的HandlerAdapter。这是一个致命错误。
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
5.浏览器请求缓存
6.在处理程序之前,调用拦截器的前置方法
springmvc拦截器源码分析-HandlerInterceptor接口_LouD_dm的博客-CSDN博客
/**
* 应用注册拦截器的preHandle方法。
*
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取所有的拦截器
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//调用前置处理方法
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
7.使用处理器适配器处理,并返回ModelAndView
RequestMappingHandlerAdapter处理HandleMethed类型的处理器
1.AbstractHandlerMethodAdapter
springmvc组件HandlerAdapter源码分析-AbstractHandlerMethodAdapter_LouD_dm的博客-CSDN博客
2.RequestMappingHandlerAdapter
springmvc组件HandlerAdapter源码分析-RequestMappingHandlerAdapter_LouD_dm的博客-CSDN博客
8.视图名称转换
/**
* 我们需要视图名称转换吗?
*/
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
9.在处理之后,调用拦截器的后置方法
/**
* 应用注册拦截器后的方法。
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
throws Exception {
//获取当前所有的拦截器
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
//调用后置处理方法
interceptor.postHandle(request, response, this.handler, mv);
}
}
}