Spring WebMVC请求处理流程源码分析

Spring WebMVC 版本:5.1.3.RELEASE

定义一个controller

1
2
3
4
5
6
7
8
9
10
11
12
13
@RequestMapping("dingtalk")
@RestController
public class DingtalkController {

@Autowired
private DingTalkService dingTalkService;

@GetMapping(value = "contact/authscope", produces = MediaType.APPLICATION_JSON_UTF8_VALUE )
public Object findContactAuthScope() {
dingTalkService.getContactAuthScope(dingTalkService.getAccessToken());
return HttpStatus.OK;
}
}

我们请求http://localhost:9000/dingtalk/contact/authscope这个URL时会调用该controller的 findContactAuthScope 方法。
那么Spring MVC是怎么实现这个处理流程的呢?

图源:SpringMVC流程架构图

我们知道 DispatcherServlet 类是Spring MVC 的入口,
每次请求都会调用它的 doService 方法,该方法又将请求委托给 doDispatch 方法处理,我们来看doDispatch方法
的实现:

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
   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);

// 1. 获取当前请求的HandlerExecutionChain,HandlerExecutionChain持有Handler对象和HandlerInterceptor,
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

// 2. 获取当前请求的Handler对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 如果HandlerMethod支持,处理 last-modified 请求头.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
// 请求资源未改变则中断处理直接返回
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// 3. 通过HandlerAdapter调用具体的HandlerMethod来处理请求,最后返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
......
// 视图解析和显示
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}

......
}

第1点getHandler方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
   @Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// 获取当前请求的拦截器列表和Handler对象
HandlerExecutionChain handler = mapping.getHandler(request);
// 这里的mapping实例是RequestMappingHandlerMapping,通过 getHandler 方法获取到的hanlder不为空
if (handler != null) {
return handler;
}
}
}
return null;
}

RequestMappingHandlerMapping 类用于从@Controller注解所在的类的@RequestMapping注解上
构建(RequestMappingInfo)请求映射信息实例。

可以看到是通过遍历HandlerMapping列表,然后调用每个HandlerMapping接口的getHandler方法,进入
实现该接口的抽象类 AbstractHandlerMapping 重写的getHandler方法实现:

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
   @Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 查询当前请求的HandlerMethod
Object handler = getHandlerInternal(request);
// 当前请求的Handler如果为空则获取默认的HandlerMethod
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// 如果handler是bean name字符串则获取对应的bean实例
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 添加HandlerMethod和HandlerInterceptor拦截器到HandlerExecutionChain中,对应handler和interceptorList成员变量
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

......
// 如果请求头包含Origin则进行跨域配置
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}

return executionChain;
}

进入到AbstractHandlerMethodMapping的getHandlerInternal方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
   @Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 查询到请求uri为 /dingtalk/contact/authscope
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
// 根据查询到的路径查询当前请求对应的HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}

到这里就查到请求的uri对应的是findContactAuthScope方法。

下一步执行第2点,获取HandlerMethod对应的HandlerAdapter,查看getHandlerAdapter方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
   protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 这里返回的是 RequestMappingHandlerAdapter 实例,继承AbstractHandlerMethodAdapter
// 用于支持@RequestMapping注解的类和方法
if (adapter.supports(handler)) {
return adapter;
}
}
}
......
}

下一步执行第3点,调用 AbstractHandlerMethodAdapter的handle方法,最终会调用子类的handleInternal方法,
该方法位于RequestMappingHandlerAdapter:

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;
// 检查给定的请求是否支持(request method)方法和所需(session)会话(如果有的话)
checkRequest(request);

// 如果需要会话同步则运行 invokeHandlerMethod 方法在同步代码块中
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 没有可用的 HttpSession -> 不需要互斥锁
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 根本不需要会话同步 ...
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方法实现:

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
   @Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
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));
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;
}
// 返回ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}

在此方法中调用了invokeAndHandle方法,实现反射调用目标方法并通过 HandlerMethodReturnValueHandler 接口的实现类处理返回结果值,
然后会调用实现了ResponseBodyAdvice 接口的类的beforeBodyWrite方法处理返回值,
最后通过实现了GenericHttpMessageConverter 接口的类将响应body写入输出流信息中。

以上,如有问题欢迎提出!

如果对您有所帮助,欢迎投食!
0%