抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

SpringMVC-DispatcherServlet流程解析

前言

​ 上一篇主要讲了SpringMVC的主要调用刘晨,本章节讲解里面的每一步的调用流程:

  1. 文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;

  2. 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);

  3. 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);

  4. 通过ViewResolver解析逻辑视图名到具体视图实现;

  5. 本地化解析;

  6. 渲染具体的视图等;

  7. 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。

checkMultipart

从这个方法名字我们能看出来它是用来检查这个请求是不是文件上传的请求的。我们具体的看一下它是怎么判断是否是文件上传的。

  • 判断是不是multipart的请求,默认的判断方式是先判断是不是”POST”请求,然后判断”contentType”是否以multipart开头。

  • 如果不满足multipart条件,直接返回request,也就是request没有做任何处理

  • 如果满足multipart基本条件, 将multipartRequest转换为StandardMultipartHttpServletRequest请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* 检查是否为multipart,如果是的话处理一下
*
* @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);
// Keep processing error dispatch with regular request handle below
} else {
throw ex;
}
}
}
}
// If not returned before: return original request.
return request;
}

// 判断是否为multipart的方法
public boolean isMultipart(HttpServletRequest request) {
// Same check as in Commons FileUpload...
if (!"post".equalsIgnoreCase(request.getMethod())) {
return false;
}
String contentType = request.getContentType();
return StringUtils.startsWithIgnoreCase(contentType, "multipart/");
}


//转换为multipart请求
@Override
public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
}

checkMultipart这个方法的源码如上所示。这里先是判断multipartResolver这个类是不是为空,我们之前分析过,multipartResolver是需要我们进行配置的,通常配置如下所示:

1
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

如果没有配置MultipartResolver的话,则认为不是文件上传的请求,如果配置了MultipartResolver的话,调用isMultipart方法验证是不是文件上传的请求,isMultipart方法的内容如下:

1
2
3
4
@Override
public boolean isMultipart(HttpServletRequest request) {
return ServletFileUpload.isMultipartContent(request);
}

getHandler

获取request的Handler方法,handler被封装为HandlerExecutionChain,HandlerExecutionChain为handler方法加上拦截器的集合。我们定义的拦截器就在HandlerExecutionChain这个类中生效。

HandlerExecutionChain为真正的Handler对象与Interceptor的组合类

这段代码的意思是获取当前请求对应的处理类,在这个处理链中会包含对应的拦截器的信息。HandlerExecutionChain这个类中包含变和不变量的两部分内容。我们具体的看一下getHandler这个方法的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//handlerMappering实例
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
//获取HandlerMethod和过滤器链的包装类
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}

getHandler

SpringMVC默认加载三个请求处理映射类:RequestMappingHandlerMapping、SimpleUrlHandlerMapping、和BeanNameUrlHandlerMapping。这三个类有一个共同的父类:AbstractHandlerMapping。在上面代码中hm.getHandler(request)这个getHandler方法在AbstractHandlerMapping中,它的子类都没有重写这个方法。我们去AbstractHandlerMapping这个类中看一下这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//这里会两个子类重写这个方法:AbstractHandlerMethodMapping和AbstractUrlHandlerMapping
//根据请求的uri拿到对应的HandlerMethod对象
Object handler = getHandlerInternal(request);
//如果没有找到的话,去默认的处理类
if (handler == null) {
handler = getDefaultHandler();
}
//如果没有默认的处理类,返回null
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}

// 这一步的目的是就是,获取所有的interceptor的对象,然后与当前的handler组合在一起
//包装为执行器链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
} else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}

//是否是跨域请求,就是查看request请求头中是否有Origin属性
if (hasCorsConfigurationSource(handler)) {
//自定义钩子方法获取跨域配置
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
//注解获取跨域配置
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
//这里设置了跨域过滤器的CorsInterceptor
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}

return executionChain;
}

HandlerExecutionChanin mappedHandler = getHandler(request),内部细节如下

  • 内部获取handler方法,在DispatcherServlet中大部分的处理都要将request或者response作为参数对象。
  • 内部获取handler的实现,获取request请求的路径,然后从mappingRegistry中拿到路径匹配的HandlerMethod. HandlerMethod封装了我们平时写的@RequestMapping等之类的方法,还有bean。这些可以通过反射获得
  • 获取到HandlerMethod之后,稍作处理封装handler和beanhandlerMethod.createWithResolvedBean()
  • 上面获取的是HandlerMethod,getHandler中再次封装handler和interceptors

这些都是为真正的处理请求做准备

getHandlerInternal

根据请求的uri拿到对应的HandlerMethod对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
//从request对象中获取uri,/common/query2
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
request.setAttribute(LOOKUP_PATH, lookupPath);
this.mappingRegistry.acquireReadLock();
try {
//根据uri从映射关系中找到对应的HandlerMethod对象
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
//把Controller类实例化
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} finally {
this.mappingRegistry.releaseReadLock();
}
}

//根据uri从映射关系中找到对应的HandlerMethod对象
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
//根据URL获取Mapping映射列表
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
//添加匹配关系的映射
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
//如果两个RequestMappinginfo什么都相同,报错
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
//遍历所有的Mapping映射
for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request);
if (match != null) {
//RequestMappingInfo对象和HandlerMethod对象封装到Match对象中,其实就是注解属性和Method对象的映射
matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
}
}
}
getHandlerExecutionChain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//把HandlerMethod对象包装到HandlerExecutionChain对象中,这个对象中有过滤器对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//获取uri
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);

//遍历拦截器列表
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
//如果adaptedInterceptors中由MappedInterceptor类型的拦截器
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
//检查是否和请求路径匹配
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
//如果匹配加入到拦截器链
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
//否则直接加入拦截器链
chain.addInterceptor(interceptor);
}
}
return chain;
}

getHandlerAdapter

HandlerAdapter接口

通过Handler获取HandlerAdpater,HandlerAdpater作为适配器,真正做东西的还是Handler,HandelAdpater做了很多的预处理,不过它的接口很简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface HandlerAdapter {

/**
* 判断当前的HandlerAdpater是否支持handler的实例,也就是当前的adapter能否使用传过来的Handler
*
* @param handler handler object to check
* @return whether or not this object can use the given handler
*/
boolean supports(Object handler);

/**
* 使用传过来的handler来处理请求
* @return a ModelAndView object with the name of the view and the required
* model data, or {@code null} if the request has been handled directly
* @throws Exception in case of errors
*/
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

/**
* 和Servlet的getLastModified功能基本一致
* @param request current HTTP request
* @param handler handler to use
* @return the lastModified value for the given handler
* @see javax.servlet.http.HttpServlet#getLastModified
* @see org.springframework.web.servlet.mvc.LastModified#getLastModified
*/
long getLastModified(HttpServletRequest request, Object handler);

}

源码分析

在DispatcherServlet中getHandlerAdapter的实现,则是遍历HandlerAdpaters,然后返回第一个支持handler的Adpater.

1
2
3
4
5
6
7
8
9
10
11
12
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
//根据handlerMethod对象,找到合适的HandlerAdapter对象,这里用到了策略模式
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");
}

这个方法就是一个策略模式,从handlerAdapters列表中找到一个合适的adapter返回,用来调用。

applyPreHandle

前置过滤器,如果为false则直接返回

然后其内部就是我们写拦截器的时候常见的preHandler方法。如果拦截器preHndle返回false,那么请求终止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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];
//调用preHandle来进行前置处理
if (!interceptor.preHandle(request, response, this.handler)) {
//如果返回false调用triggerAfterCompletion从失败的地方倒叙调用后置过滤器释放资源
triggerAfterCompletion(request, response, null);
return false;
}
//记录当前调用到的索引
this.interceptorIndex = i;
}
}
return true;
}

triggerAfterCompletion

如果一个过滤器失败了从调用的地方倒序调用后置过滤器释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
//获取到过滤器数组
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//从失败的地方倒序循环调用
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
//调用后置处理器释放资源
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}

handle

执行解析handler中的args,调用(invoke) controller的方法。得到视图

1
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

HandlerAdpater让Handler处理request与response,RequestMappingHandlerAdpater是最复杂的一个实现,也是大部分请求中都用到的一个Adpater.

ha.handle这个方法会调用org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter中的handle方法,这个方法里面很简单,就是调用了handleInternal这个方法,代码如下:

1
2
3
4
5
6
7
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

return handleInternal(request, response, (HandlerMethod) handler);
}

handleInternal

而handleInternal这个方法调用的是org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter中的handleInternal方法,我们进入到这个方法中看看这个方法中都干了一些什么事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ModelAndView mav;
//检查是不是所支持的请求类型、是不是要求session
checkRequest(request);

// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
//session中是不是要求同步执行
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
//同步执行方法调用
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
//Controller里面具体方法调用,重点看
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
//缓存的设置
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
} else {
prepareResponse(response);
}
}

return mav;
}

在上面的这个方法中我们需要关注的是invokeHandlerMethod这个方法。

invokeHandlerMethod

invokeHandlerMethod这个方法有点复杂,这个方法中干了很多的事,像创建数据验证类、创建方法处理类、模型视图容器等。在这里我们先忽略这些,直接跳到invokeHandlerMethod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
//获取数据绑定工厂 @InitBinder注解支持,没太多用
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
//Model工厂,收集了@ModelAttribute注解的方法
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

//可调用的方法对象
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
//设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
//设置返回值解析器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
//设置参数绑定工厂
invocableMethod.setDataBinderFactory(binderFactory);
//设置参数名称解析类
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
//调用有@ModelAttribute注解的方法。每次请求都会调用有@ModelAttribute注解的方法
//把@ModelAttribute注解的方法的返回值存储到 ModelAndViewContainer对象的map中了
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

//异步处理
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}

//Controller方法调用,重点看看
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

return getModelAndView(mavContainer, modelFactory, webRequest);
} finally {
webRequest.requestCompleted();
}
}
invokeAndHandle

调用Controller的核心方法,完成参数的转换封装以及返回值的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

//具体调用逻辑,重点看
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);

if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
//返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}

这个方法在org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod中。在这个方法中我们只关注第一句话:

1
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
invokeForRequest

在invokeForRequest这个方法中,主要干了两件事,一是解析请求参数,二是调用Controller中的请求方法。

1
2
3
4
5
6
7
8
9
10
11
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

//获取参数数组,重点看
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
getMethodArgumentValues

请求解析的方法是getMethodArgumentValues,这个是我们要分析的重点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {

//入参的包装类,里面包装了参数类型,参数名称,参数注解等等信息
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}

Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
//设置参数名称解析器
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}

//典型的策略模式,根据parameter能否找到对应参数的处理类,能找到就返回true
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
//具体参数值解析过程,重点看看
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
// Leave stack trace for later, exception may actually be resolved and handled...
if (logger.isDebugEnabled()) {
String exMsg = ex.getMessage();
if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, exMsg));
}
}
throw ex;
}
}
return args;
}
supportsParameter

典型的策略模式,根据parameter能否找到对应参数的处理类,能找到就返回true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public boolean supportsParameter(MethodParameter parameter) {
//获取参数解析器
return getArgumentResolver(parameter) != null;
}

@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//从缓存中获取参数解析器
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
//遍历参数解析器
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
//进行匹配
if (resolver.supportsParameter(parameter)) {
result = resolver;
//将匹配的加入缓存
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}

​ 该方法主要是进行参数解析器的验证,检查释放有对应的解析器,如果有放进缓存中,如果没有对应类型的解析器就抛出异常

这里面有一个方法supportsParameter,会对SpringMVC支持的26个参数解析器进行解析

resolveArgument

具体参数的解析过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
@Nullable
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

//根据参数获取对应参数的解析类
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);

//如果没有能解析方法参数的类,抛出异常
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
//策略模式去调用具体参数解析类
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
getArgumentResolver

从缓存中获取对应的解析器,如果不存在则再次进行匹配校验,直到找到一个合适的参数解析器放进缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//从缓存中获取参数解析器
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
//遍历参数解析器
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
//进行匹配
if (resolver.supportsParameter(parameter)) {
result = resolver;
//将匹配的加入缓存
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}

然后就是使用具体的参数解析类进行参数解析

1
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
doInvoke

通过反射调用Controller对应的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
//通过反射调用controller
return getBridgedMethod().invoke(getBean(), args);
} catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(formatInvokeError(text, args), ex);
} catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
} else if (targetException instanceof Error) {
throw (Error) targetException;
} else if (targetException instanceof Exception) {
throw (Exception) targetException;
} else {
throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
}
}
}
handleReturnValue

返回值的处理

1
2
3
4
5
6
7
8
9
10
11
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//选择合适的返回值处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
//调用对应的处理器对返回值做处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
selectHandler

返回匹配的返回值处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
//遍历所有的HandlerMethodReturnValueHandler
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
//如果是异步的并且不是AsyncHandlerMethodReturnValueHandler类型的
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
//跳出本地循环进入下一个循环
continue;
}
//如果类型匹配
if (handler.supportsReturnType(returnType)) {
//将返回值处理器返回
return handler;
}
}
return null;
}

获取到HandlerMethodReturnValueHandler然后就是调用handleReturnValue方法进行返回值的处理

1
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

到这里就完成了invokeAndHandle的主要内容,完成了参数解析,controller调用以及返回值的处理

getModelAndView

获取创建ModelAndView,并对一些参数进行设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

modelFactory.updateModel(webRequest, mavContainer);
//这个地方的值会在@ResponseBody注解的时候设置为true
//所以如果是@ResponseBody的controller的话直接返回不进行页面跳转
if (mavContainer.isRequestHandled()) {
return null;
}
//得到defaultModel或者是redirectModel
ModelMap model = mavContainer.getModel();
/*
* 注意mavContainer.getViewName()方法,如果mavContainer的Object view是一个String类型,
* 则返回该字符串;如果不是,则得到null
*/
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
if (!mavContainer.isViewReference()) {
mav.setView((View) mavContainer.getView());
}
//如果是RedirectAttributes类型的
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
if (request != null) {
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
}
return mav;
}

applyDefaultViewName

该方法主要是用来应用默认的视图名称

如果在控制器没有设置viewName,则用使用默认的视图名称

1
2
3
4
5
6
7
8
9
10
11
12
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
//如果ModelAndView不为空并且没有跳转的路径设置
if (mv != null && !mv.hasView()) {
//获取默认的视图名称
String defaultViewName = getDefaultViewName(request);
//不为空则设置ViewName
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}

applyPostHandle

中置过滤器,调用过滤器postHandle方法,注意是倒序调用的

1
2
3
4
5
6
7
8
9
10
11
12
13
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];
//调用过滤器的postHandle方法
interceptor.postHandle(request, response, this.handler, mv);
}
}
}

processDispatchResult

处理返回的结果集的核心方法,主要完成异常的处理,视图的渲染以及后置处理器的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {

boolean errorView = false;
//如果异常不为空
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
} else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//调用异常处理器
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}

//视图渲染,响应视图
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}

if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}

//后置过滤器
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAfterCompletion(request, response, null);
}
}

processHandlerException

异常处理器的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {

// Success and error responses may use different content types
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
//遍历异常处理器
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
//调用异常处理器的resolveException方法
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
//在request中设置异常信息
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
//如果没有设置viewName
if (!exMv.hasView()) {
//获取默认的viewName
String defaultViewName = getDefaultViewName(request);
//并设置默认的viewName
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using resolved error view: " + exMv, ex);
} else if (logger.isDebugEnabled()) {
logger.debug("Using resolved error view: " + exMv);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}

throw ex;
}

render

该方法是视图渲染的核心方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);

View view;
//从ModelAndView中获取viewName
String viewName = mv.getViewName();
//如果viewName不为空
if (viewName != null) {
// We need to resolve the view name.
// 如果视图名不为空,需要解析视图名
//解析视图的调用栈如下图所示
//传入的是视图名字,Model,locale和request
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
} else {
// No need to lookup: the ModelAndView object contains the actual View object.
//如果viewName为空
//尝试直接获取view
view = mv.getView();
//如果还是为空就报错
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}

// Delegate to the View object for rendering.
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
//核心逻辑在这里
view.render(mv.getModelInternal(), request, response);
} catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
resolveViewName

决定使用哪一个ViewName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {

if (this.viewResolvers != null) {
//遍历所有的视图解析器
for (ViewResolver viewResolver : this.viewResolvers) {
//调用resolveViewName方法获取对应的视图解析器
View view = viewResolver.resolveViewName(viewName, locale);
//如果不为空就返回获取的view
if (view != null) {
return view;
}
}
}
return null;
}
render

调用对应视图解析器的render

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {

if (logger.isDebugEnabled()) {
logger.debug("View " + formatViewName() +
", model " + (model != null ? model : Collections.emptyMap()) +
(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}

// 创建整合后需要返回给浏览器的Model
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
// 设置response 报文头
prepareResponse(request, response);
// 渲染数据,通过模板方法由子类实现,如InternalResourceView
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

这里面最核心的方法是renderMergedOutputModel,通过调用实现类来实现的,SpirngMVC有一下的实现类:

其中最常用的就是InternalResourceView,jsp的视图解析器

InternalResourceView#renderMergedOutputModel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

//把响应数据设置到request对象中
// Expose the model object as request attributes.
exposeModelAsRequestAttributes(model, request);

// 本类中的此函数是空函数,留给子类比如JstlView去实现自定义逻辑
// Expose helpers as request attributes, if any.
exposeHelpers(request);

//获取到跳转的地址
// Determine the path for the request dispatcher.
String dispatcherPath = prepareForRendering(request, response);

// Obtain a RequestDispatcher for the target resource (typically a JSP).
// 获取跳转控制器RequestDispatcher
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}

// If already included or response already committed, perform include, else forward.
// 如果是incloud直接返回用户资源
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including [" + getUrl() + "]");
}
rd.include(request, response);
}
// 其他情况,携带request和response跳转到另一个控制器方法
else {
// Note: The forwarded resource is supposed to determine the content type itself.
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to [" + getUrl() + "]");
}
//进行forward跳转
rd.forward(request, response);
}
}

​ 至此,View渲染视图的大致流程结束,也就是Spring MVC基本完成了整个流程,剩下的渲染工作交由Servlet去处理。

triggerAfterCompletion

调用后置处理器释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
throws Exception {
//获取到过滤器数组
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//从失败的地方倒序循环调用
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
//调用后置处理器释放资源
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}

到此位置 整个DispatcherServlet的基本调用流程已经讲清楚了。

总结

DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:

  1. 文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;

  2. 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);

  3. 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);

  4. 通过ViewResolver解析逻辑视图名到具体视图实现;

  5. 本地化解析;

  6. 渲染具体的视图等;

  7. 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。

DispatcherServlet中使用的特殊的Bean

DispatcherServlet默认使用WebApplicationContext作为上下文,因此我们来看一下该上下文中有哪些特殊的Bean:

  1. Controller:处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理;

  2. HandlerMapping:请求到处理器的映射,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象;如BeanNameUrlHandlerMapping将URL与Bean名字映射,映射成功的Bean就是此处的处理器;

  3. HandlerAdapter:HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;如SimpleControllerHandlerAdapter将对实现了Controller接口的Bean进行适配,并且掉处理器的handleRequest方法进行功能处理;

  4. ViewResolver:ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;如InternalResourceViewResolver将逻辑视图名映射为jsp视图;

  5. LocalResover:本地化解析,因为Spring支持国际化,因此LocalResover解析客户端的Locale信息从而方便进行国际化;

  6. ThemeResovler:主题解析,通过它来实现一个页面多套风格,即常见的类似于软件皮肤效果;

  7. MultipartResolver:文件上传解析,用于支持文件上传;

  8. HandlerExceptionResolver:处理器异常解析,可以将异常映射到相应的统一错误界面,从而显示用户友好的界面(而不是给用户看到具体的错误信息);

  9. RequestToViewNameTranslator:当处理器没有返回逻辑视图名等相关信息时,自动将请求URL映射为逻辑视图名;

  10. FlashMapManager:用于管理FlashMap的策略接口,FlashMap用于存储一个请求的输出,当进入另一个请求时作为该请求的输入,通常用于重定向场景,后边会细述。

评论