引言
在上一篇文章【SpringMVC 篇(二)DispatcherServlet 请求】 中,主要介绍了一下请求预处理以及相关流程。这篇文章将介绍消息转换器,消息转换器就是将请求参数、响应结果进行反序列化以及序列化。@RequestBody 以及 @ResponseBody、异步等的处理都是在该阶段进行的。
HttpMessageConverter<T>
消息转换器的顶级接口,该接口使用策略模式,根据当前请求获取出对应的转换器。我们看一下该接口都包含哪些方法:
// 判断当前转换器是否支持当前请求的参数解析(反序列化过程)
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
// 判断当前转换器是否支持当前请求的响应处理(序列化过程)
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
// 当前转换器支持的媒体类型
List<MediaType> getSupportedMediaTypes();
// 负责对请求参数进行解析
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
// 将结果进行序列化
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
接口比较简单,无非就是请求进来的时候,判断当前转换器是否支持,如果支持 ,canRead 就会对请求参数进行解析;当进行响应的时候,判断当前转换器是否支持,如果支持, canWrite 方法就会对结果进行处理。
HandlerMethodArgumentResolver
HandlerMethodArgumentResolver 是一个策略接口,主要用于提供参数解析的抽象。
// 判断当前参数解析器是否支持当前参数对象
boolean supportsParameter(MethodParameter parameter);
// 如果支持,那么解析的具体流程由该方法完成
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
该接口也十分简单,就只有两个方法,主要用于请求参数的解析。有了请求参数的解析,那么肯定也会有响应结果的处理。我们看一下负责处理响应的接口。
HandlerMethodReturnValueHandler
跟 HandlerMethodArgumentResolver 接口类似,该接口同样也只提供了两个方法。我们看一下它的代码。
// 当前解析器是否支持当前返回值处理
boolean supportsReturnType(MethodParameter returnType);
// 处理返回值的具体抽象
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
RequestResponseBodyMethodProcessor
该接口是一个聚合接口,实现了 HandlerMethodArgumentResolver 及 HandlerMethodReturnValueHandler。
-
UML 图
-
关键源码
// 我们可以看到,这里判断是否支持参数的解析是建立在该参数是否包含 @RequestBody 这个注解基础之上的
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
// HandlerMethodArgumentResolver 接口的实现方法
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
// 参数对象的封装器,可以从该对象中获取参数类型、参数名、参数注解、所在方法等
parameter = parameter.nestedIfOptional();
// 调用方法将参数进行解析
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
// 当前的参数名
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
// 这里其实就是参数校验了,也就是 @Validated 注解生效的地方(该方法由 RequestResponseBodyMethodProcessor 的父类 AbstractMessageConverterMethodArgumentResolver 提供)
validateIfApplicable(binder, parameter);
// 获取校验结果
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
// 通过消息解析器解析参数
@Override
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
Assert.state(servletRequest != null, "No HttpServletRequest");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
// 具体的解析操作交给了它的父类
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString(), inputMessage);
}
return arg;
}
/*==========================以下是返回值的相关处理==========================*/
// 如果 Controller 包含了 @ResponseBody 或者 Controller 方法包含 @ResponseBody,那么该转换器就会生效
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
// 处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 调用解析器处理返回值,ResponseBodyAdvice 会在这步被调用
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
AbstractMessageConverterMethodArgumentResolver
// 子类通过该方法进行参数处理
@SuppressWarnings("unchecked")
@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
// 获取媒体类型
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class<?> contextClass = parameter.getContainingClass();
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class<T>) resolvableType.resolve();
}
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
// 这里开始遍历消息转换器,获取支持当前参数解析的消息转换器
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
// 判断是否支持解析
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
// 这里是 Advice 增强的前置方法调用
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
// 调用真实的消息转换器进行参数解析
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
// 这里是 Advice 增强的后置方法调用
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
}
else {
// 调用 Advice 处理空参数的情况
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
MediaType selectedContentType = contentType;
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
});
return body;
}
/*==========================以下是返回值的相关处理==========================*/
@SuppressWarnings({"rawtypes", "unchecked"})
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
Object body;
Class<?> valueType;
Type targetType;
if (value instanceof CharSequence) {
body = value.toString();
valueType = String.class;
targetType = String.class;
}
else {
// 返回值
body = value;
// 返回值类型
valueType = getReturnValueType(body, returnType);
targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
}
if (isResourceType(value, returnType)) {
outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
outputMessage.getServletResponse().getStatus() == 200) {
Resource resource = (Resource) value;
try {
List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
body = HttpRange.toResourceRegions(httpRanges, resource);
valueType = body.getClass();
targetType = RESOURCE_REGION_LIST_TYPE;
}
catch (IllegalArgumentException ex) {
outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
}
}
}
MediaType selectedMediaType = null;
MediaType contentType = outputMessage.getHeaders().getContentType();
boolean isContentTypePreset = contentType != null && contentType.isConcrete();
if (isContentTypePreset) {
if (logger.isDebugEnabled()) {
logger.debug("Found 'Content-Type:" + contentType + "' in response");
}
selectedMediaType = contentType;
}
else {
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);
if (body != null && producibleTypes.isEmpty()) {
throw new HttpMessageNotWritableException(
"No converter found for return value of type: " + valueType);
}
List<MediaType> mediaTypesToUse = new ArrayList<>();
for (MediaType requestedType : acceptableTypes) {
for (MediaType producibleType : producibleTypes) {
if (requestedType.isCompatibleWith(producibleType)) {
mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
}
}
}
if (mediaTypesToUse.isEmpty()) {
if (body != null) {
throw new HttpMediaTypeNotAcceptableException(producibleTypes);
}
if (logger.isDebugEnabled()) {
logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
}
return;
}
MediaType.sortBySpecificityAndQuality(mediaTypesToUse);
for (MediaType mediaType : mediaTypesToUse) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
break;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Using '" + selectedMediaType + "', given " +
acceptableTypes + " and supported " + producibleTypes);
}
}
if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
// 遍历获取合适的消息转换器对返回值进行处理
for (HttpMessageConverter<?> converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter<?>) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
// 这里进行 Advice 增强的回调
body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
inputMessage, outputMessage);
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->
"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Nothing to write: null body");
}
}
return;
}
}
}
if (body != null) {
Set<MediaType> producibleMediaTypes =
(Set<MediaType>) inputMessage.getServletRequest()
.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {
throw new HttpMessageNotWritableException(
"No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");
}
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}
- 分析
这里对一些关键的代码进行了说明。在进行接下来的分析之前,我们先对以上的内容进行总结与梳理。文章开始的时候介绍了消息转换器顶级接口 HttpMessageConverter<T>,稍后又介绍了两个接口,HandlerMethodArgumentResolver 用来处理方法参数的解析,HandlerMethodReturnValueHandler 用来进行返回值的解析。 RequestResponseBodyMethodProcessor 同时实现了HandlerMethodArgumentResolver 以及 HandlerMethodReturnValueHandler 这两个接口,同时具备了参数解析与返回值处理的功能。而具体的参数、返回值的解析处理操作其实是调用了 HttpMessageConverter<T> 接口的实现。对于 @Validated 以及 RequestBodyAdvice、ResponseBodyAdvice<T> 接口的调用也是在这一阶段完成的。
HandlerMethod
以上的内容是对下游相关方法的调用解析,那么接下来我们将会介绍一下上游的方法调用,也就是说什么时候会触发相关参数的解析。那么首先需要介绍的类就是 HandlerMethod。前文提到过 MethodParameter,也就是对方法参数的封装,对参数的访问提供类便捷的方式。而 HandlerMethod 是对 Controller 方法的封装,对外提供了便捷访问相关属性的方法,比如:方法对象、方法参数、包含的注解、Http 状态码等。
InvocableHandlerMethod
HandlerMethod 的子类,提供了参数解析器的聚合器HandlerMethodArgumentResolverCompositeServletInvocableHandlerMethod
InvocableHandlerMethod 的子类,提供返回值解析器的聚合器 ServletInvocableHandlerMethod
ResolverComposite
解析器聚合器其实就是两组代理类。一个负责参数的解析,一个负责返回值的处理。它们内部都包含对应的解析器集合。
-
HandlerMethodArgumentResolverComposite
参数解析器聚合器,除了包含对应的解析器集合外,它还提供了一个参数对象与解析器组合的缓存。
// 参数解析器集合
private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
// 缓存
private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
new ConcurrentHashMap<>(256);
// 根据方法参数获取对应的解析器,同时将二者绑定放到缓存里
@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;
}
-
HandlerMethodReturnValueHandlerComposite
包含返回值处理器的集合。
// 解析处理器集合
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
大家可以思考一下,为什么返回值聚合器没有提供类似于参数解析器的缓存呢?代码比较简单,所以这里就不过多介绍了。
RequestMappingHandlerAdapter
到目前为止,我们都在介绍消息转换器。但是如何跟上一节的请求处理联系起来呢?RequestMappingHandlerAdapter 就是来做这个工作的,那么具体是怎么联系起来的,我们继续回到上一节 DispathcerServlet 中的 doDispatch() 方法。
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据当前请求处理器获取指定的处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// GET、HEAD 请求优化
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;
}
// 请求处理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
这里我们关注三个方法,一个是 getHandler(processedRequest); 一个是 getHandlerAdapter(mappedHandler.getHandler());最后一个是 ha.handle(processedRequest, response, mappedHandler.getHandler()) 方法。
-
getHandler(processedRequest)
根据当前请求获取其对应的处理器,也就是拿到请求的 URL 对应的 Controller 方法以及拦截器等(相当于一个执行器链)
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
// 这里拿到的就是默认的 RequestMappingHandlerMapping
for (HandlerMapping mapping : this.handlerMappings) {
// 通过 RequestMappingHandlerMapping 获取对应的执行器链
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
-
getHandlerAdapter(mappedHandler.getHandler())
获取处理器适配器,默认是 RequestMappingHandlerAdapter 。
// 获取处理器适配器
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");
}
-
ha.handle(processedRequest, response, mappedHandler.getHandler())
handle 是 AbstractHandlerMethodAdapter 的抽象方法,它将具体的逻辑交给了 AbstractHandlerMethodAdapter 的子类 RequestMappingHandlerAdapter 的 handleInternal 方法。
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
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 {
// 不需要加锁执行
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;
}
// 调用处理器方法执行具体的处理逻辑
@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 对象,这个对象在本文中已经介绍过了
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);
}
// 执行方法调用
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
ServletInvocableHandlerMethod
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 这个地方已经经过了参数解析以及 Controller 方法调用,并且拿到了方法的返回值,returnValue 就是要交给返回值处理器处理的对象。
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;
}
}
InvocableHandlerMethod
// 处理请求参数的解析
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取 Controller 方法的请求参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
return doInvoke(args);
}
// 请求参数的解析
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;
}
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;
}
以上就是分别处理参数以及返回值的具体流程。内容有点长,这里只能挑一些重点进行讲解。后续可能会出一个总结篇,把请求到完成的链路做出来。对大家理解整个流程可能会更有帮助。
尾声
消息转换器就为大家讲到这里,到目前为止,介绍的请求其实都是同步请求。而 SpringMVC 同样支持异步的请求处理,那么它的异步是如何实现的呢?我将在下一篇文章【SpringMVC 篇(四)异步处理】中为大家详细介绍。