一. 准备
接着上一篇,我们暴露的接口:
@RestController
public class IndexController {
@GetMapping("/hello")
public String hello(String name) {
return "hello: " + name;
}
}
bebug到DispatcherServlet#doDispatch
:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 1. 关注点一
mappedHandler = getHandler(processedRequest);
// 2. 关注点二
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 3. todo待分析,关注点三
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 4. todo待分析,关注点四
applyDefaultViewName(processedRequest, mv);
// 5. todo待分析,关注点五
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
二. 分析
1. 关注几个属性值
我们先看一下DispatcherServlet
内部几个属性此时的值:
/** List of HandlerMappings used by this servlet. */
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet. */
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet. */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet. */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** List of ViewResolvers used by this servlet. */
@Nullable
private List<ViewResolver> viewResolvers;
handlerMappings
handlerAdapters
handlerExceptionResolvers
viewNameTranslator
viewResolvers
2. 关注点三源码
mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
执行具体的handler
并返回ModelAndView
对象;从Post not found: SpringMvc源码分析4.1——HandlerAdapter SpringMvc源码分析4.1——HandlerAdapter可以知道,这里的ha
为RequestMappingHandlerAdapter
。顺序执行链我们最终定位到RequestMappingHandlerAdapter#handleInternal
,源码如下:
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// 校验请求的method和是否需要session
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
// 这里有一个配置,因为session不是线程安全的,这里可以配置使其同步执行
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
// todo待分析
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 删减
....
return mav;
}
该方法里面首先进行了一个校验checkRequest
主要是校验请求的method
和是否需要session
。然后做了一个是否需要在session
上的同步判断。该synchronizeOnSession
默认值为false
的,默认Session
是有线程安全问题的,如果这个值设置为true
而且有session
的话,就会同步执行invokeHandlerMethod()
,从而避免session
的线程安全问题。接着,再调用mav = invokeHandlerMethod(request, response, handlerMethod);
执行handler
:
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 包含了对@InitBinder的处理
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 包含了对@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));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 删除异步请求的处理代码
...
// 调用方法并通过配置的HandlerMethodReturnValueHandlers之一来处理返回值。重点关注
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
到这,我们先来看一下RequestMappingHandlerAdapter
里面的几个属性此时的值:
// 自定义参数解析器,会后于内置的参数解析器
@Nullable
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
// 参数解析器
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
// 在{@code @InitBinder}方法中配置支持的参数类型
@Nullable
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
// 自定义返回值处理器,会后于内置的返回值处理器
@Nullable
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
// 返回值处理器
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
// 消息转换器
private List<HttpMessageConverter<?>> messageConverters;
// RequestBodyAdvice或者ResponseBodyAdvice
private List<Object> requestResponseBodyAdvice = new ArrayList<>();
- customArgumentResolvers
此时为空,没有自定义
- argumentResolvers
- initBinderArgumentResolvers
- customReturnValueHandlers
为空,没有自定义
- returnValueHandlers
- messageConverters
- requestResponseBodyAdvice
从源码上看,我们需要重点关注一下invocableMethod.invokeAndHandle(webRequest, mavContainer);
,如下:
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 {
// 重点关注,调用匹配的HandlerMethodReturnValueHandler
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
这个方法,里面就包括了handler
方法参数的解析,方法的处理,返回值的处理等,这需要我们重点分析。分析这一块我们能看到@RequestParam
,@RequestBody
,@ResponseBody
等的处理过程。内容有点多,放到下一节单独分析。
三. 总结
到此,我们大概分析了一下ha.handle(processedRequest, response, mappedHandler.getHandler())
的执行逻辑。这其中有很多复杂的逻辑,由于我们的测试请求很简单,项目也没有做什么其他的配置,所以很多流程代码执行不到。但是没关系,我们从简单的做起,也能了解得到SpringMvc
处理请求一个大概的流程。OK,回顾一下,这一节主要了解到了:
synchronizeOnSession
的作用;- 参数值的解析,需要用到
argumentResolvers
,todo分析; - 返回值的主力需要用到
returnValueHandlers
,todo分析;