纵观全局
我们先进入DIspatchServlet.doDispatch()
,我们分析其调用过程的主要方法如下:
// 根据请求拿到具体的处理器方法HandlerMethod并获取拦截器包装成HandlerExecutionChain
mappedHandler = getHandler(processedRequest);
// 根据HandlerMethod得到对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// HandlerAdapter调用HandlerMethod,这里会发生参数的自动转换
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
获取HandlerExecutionChain
如上图所示,SpringMVC中内置了8个handlerMappings
处理器,用于不同类型的映射处理,使用迭代的方式一个个的去处理,不支持的实现在解析时会返回null
我们使用的是@RequestMapping
因此对应的是RequestMappingHandlerMapping
这个实现,这个实现的getHandler方法使用的是父类的方法,以下删除了部分代码,仅保留核心相关实现
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
getHandlerInternal()
用于根据请求路径查找匹配的HandlerMethod
,SpringMVC启动时会解析所有RequestMapping
的请求路径注册到mappingRegistry
中
getHandlerExecutionChain()
用于根据请求路径查找符合条件的拦截器
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
构建包装了HandlerMethod
的HandlerExecutionChain
,遍历注册的拦截器并进行匹配,如果匹配将加入到HandlerExecutionChain
中
最后将HandlerExecutionChain
返回
获取HandlerAdapter
我们知道SpringMVC通过HandlerAdapter
来调用具体的处理器,从而实现与具体处理器的解耦,因此需要根据处理器类型来拿到类型匹配的HandlerAdapter
同样是进行一个迭代的匹配,这里使用的是RequestMappingHandlerAdapter
这个实现,它的support方法为
public final boolean supports(Object handler) {
//即判断handler是否是一个HandlerMethod类型,后面的supportsInternal固定返回True
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
调用HandlerMethod
根据调用链一路来到invokeHandlerMethod
,删除了其他代码
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);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
invocableMethod.invokeAndHandle(webRequest, mavContainer);
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
我们注意到这里有四个方法
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
他们就是负责处理参数和结果类型转换的,SpringMVC内置了多种参数类型转换和结果类型转换的处理器
这里将处理器设置进去后,进入invocableMethod.invokeAndHandle(webRequest, mavContainer);
开始调用
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 这里会进行入参类型转换
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 这里会进行返回类型转换
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
- 入参转换
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
Object returnValue = doInvoke(args);
return returnValue;
}
private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
}
}
return args;
}
argumentResolvers
是HandlerMethodArgumentResolverComposite
类型,内部封装了37个具体的参数解析器,属于设计模式中的组合模式。
这里同样使用组合模式对所有的解析器进行迭代,如果支持参数解析则进行解析并返回解析后的参数值。
2. 返回值转换
与入参转换流程基本一致,组合模式遍历选择处理器并进行处理
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
由于是Rest模式,因此这里的类型处理器为RequestResponseBodyMethodProcessor
,其实现为
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
注意这里的writeWithMessageConverters
,这里会进行HttpMessageConverter
的转换将返回值再转换为对应的格式
迭代所有消息转换器,判断是否支持请求的媒体类型来进行转换处理
拦截器调用
如图在DIspatcherServlet.doService
方法中,通过
mappedHandler.applyPreHandle(processedRequest, response)
mappedHandler.applyPostHandle(processedRequest, response, mv);
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); --> mappedHandler.triggerAfterCompletion(request, response, null);
三个方法来调用三中拦截器
总结
至此,一个大概的请求流程就走完了,这里对视图等没有讲解,仅针对最基本的Rest流程进行讲解