HandlerAdapter 组件HandlerAdapter 组件,处理器的适配器。因为处理器 由于 HandlerMapping 组件涉及到的内容较多,考虑到内容的排版,所以将这部分内容拆分成了五个模块,依次进行分析: HandlerAdapter 组件(四)之 HandlerMethodReturnValueHandler本文是接着《HandlerAdapter 组件(三)之 HandlerMethodArgumentResolver》一文来分享 HandlerMethodReturnValueHandler 组件。在 回顾先来回顾一下 public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // <1> 执行调用 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // <2> 设置响应状态码 setResponseStatus(webRequest); // <3> 设置 ModelAndViewContainer 为请求已处理,返回,和 @ResponseStatus 注解相关 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; } // <4> 设置 ModelAndViewContainer 为请求未处理 mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { // <5> 处理返回值 this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
HandlerMethodReturnValueHandler 接口
public interface HandlerMethodReturnValueHandler { /** * 是否支持该类型 */ boolean supportsReturnType(MethodParameter returnType); /** * 处理返回值 */ void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; } 类图因为返回结果类型是多变的,所以会有许多的 HandlerMethodReturnValueHandler 的实现类,上图仅列出了本文会分析的两个实现类 ModelAndViewContainer
构造方法public class ModelAndViewContainer { /** * 是否在 redirect 重定向时,忽略 {@link #redirectModel} */ private boolean ignoreDefaultModelOnRedirect = false; /** * 视图,Object 类型。 * * 实际情况下,也可以是 String 类型的逻辑视图 */ @Nullable private Object view; /** * 默认使用的 Model 。实际上是个 Map */ private final ModelMap defaultModel = new BindingAwareModelMap(); /** * redirect 重定向的 Model ,在重定向时使用。 */ @Nullable private ModelMap redirectModel; /** * 处理器返回 redirect 视图的标识 */ private boolean redirectModelScenario = false; /** * Http 响应状态 */ @Nullable private HttpStatus status; private final Set<String> noBinding = new HashSet<>(4); private final Set<String> bindingDisabled = new HashSet<>(4); /** * 用于设置 SessionAttribute 的标识 */ private final SessionStatus sessionStatus = new SimpleSessionStatus(); /** * 请求是否处理完的标识 */ private boolean requestHandled = false; } getModel
public ModelMap getModel() { // 是否使用默认 Model if (useDefaultModel()) { return this.defaultModel; } else { if (this.redirectModel == null) { this.redirectModel = new ModelMap(); } return this.redirectModel; } } /** * Whether to use the default model or the redirect model. */ private boolean useDefaultModel() { return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect)); }
View 相关的方法public void setViewName(@Nullable String viewName) { this.view = viewName; } @Nullable public String getViewName() { return (this.view instanceof String ? (String) this.view : null); } public void setView(@Nullable Object view) { this.view = view; } @Nullable public Object getView() { return this.view; } public boolean isViewReference() { return (this.view instanceof String); } requestHandled 属性请求是否处理完的标识 关于
处理完结果后,接下来 // RequestMappingHandlerAdapter.java @Nullable private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); // 情况一,如果 mavContainer 已处理,则返回“空”的 ModelAndView 对象。 if (mavContainer.isRequestHandled()) { return null; } // 情况二,如果 mavContainer 未处理,则基于 `mavContainer` 生成 ModelAndView 对象 ModelMap model = mavContainer.getModel(); // 创建 ModelAndView 对象,并设置相关属性 ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } 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; } 看到没,如果已处理,则返回的 HandlerMethodReturnValueHandlerComposite
构造方法public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler { /** HandlerMethodReturnValueHandler 数组 */ private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>(); } 在《HandlerAdapter 组件(一)之 HandlerAdapter》的RequestMappingHandlerAdapter小节的 getReturnValueHandler
@Nullable private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) { for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (handler.supportsReturnType(returnType)) { return handler; } } return null; } 很简单,遍历所有的 HandlerMethodReturnValueHandler 实现类,如果支持这个返回结果,则直接返回 这里为什么不加缓存呢? supportsReturnType
@Override public boolean supportsReturnType(MethodParameter returnType) { return getReturnValueHandler(returnType) != null; } 实际上就是调用 handleReturnValue
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // <x> 获得 HandlerMethodReturnValueHandler 对象 HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); } 这里好奇的是没有调用 @Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { // 判断是否为异步返回值 boolean isAsyncValue = isAsyncReturnValue(value, returnType); // 遍历 HandlerMethodReturnValueHandler 数组,逐个判断是否支持 for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } // 如果支持,则返回 if (handler.supportsReturnType(returnType)) { return handler; } } return null; } private boolean isAsyncReturnValue(@Nullable Object value, MethodParameter returnType) { for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (handler instanceof AsyncHandlerMethodReturnValueHandler && ((AsyncHandlerMethodReturnValueHandler) handler).isAsyncReturnValue(value, returnType)) { return true; } } return false; } 在 【重点】RequestResponseBodyMethodProcessor
因为前后端分离之后,后端基本是提供 Restful API ,所以 RequestResponseBodyMethodProcessor 成为了目前最常用的 HandlerMethodReturnValueHandler 实现类。 从图中,我们也会发现,RequestResponseBodyMethodProcessor 也是 HandlerMethodArgumentResolver 的实现类。示例代码: @RestController @RequestMapping("/user") public class UserController { @RequestMapping("/walks") public List<User> walk(@RequestBody User user) { List<User> users = new ArrayList(); users.add(new User().setUsername("nihao")); users.add(new User().setUsername("zaijian")); return users; } } 虽然, 构造方法public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters) { super(converters); } public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager) { super(converters, manager); } public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable List<Object> requestResponseBodyAdvice) { super(converters, null, requestResponseBodyAdvice); } public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) { super(converters, manager, requestResponseBodyAdvice); } }
supportsParameter实现 @Override public boolean supportsParameter(MethodParameter parameter) { // 该参数是否有 @RequestBody 注解 return parameter.hasParameterAnnotation(RequestBody.class); } 该方法参数是否有 resolveArgument实现 @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) { 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()); } } // 返回方法入参对象,如果有必要,则通过 Optional 获取对应的方法入参 return adaptArgumentIfNecessary(arg, parameter); } 调用 【核心】readWithMessageConverters从请求体中解析出方法入参,方法如下: @Override protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { // <1> 创建 ServletServerHttpRequest 请求对象 HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Assert.state(servletRequest != null, "No HttpServletRequest"); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); // <2> 读取请求体中的消息并转换成入参对象 Object arg = readWithMessageConverters(inputMessage, parameter, paramType); // <3> 校验方法入参对象 if (arg == null && checkRequired(parameter)) { throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage); } return arg; } // AbstractMessageConverterMethodArgumentResolver.java @Nullable protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { // <1> 获取使用的 MediaType 对象 MediaType contentType; boolean noContentType = false; try { // <1.1> 从请求头中获取 "Content-Type" contentType = inputMessage.getHeaders().getContentType(); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { noContentType = true; // <1.2> 为空则默认为 application/octet-stream contentType = MediaType.APPLICATION_OCTET_STREAM; } // <2> 获取方法参数的 containing class 和 目标类型,用于 HttpMessageConverter 解析 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(); } // <3> 获取 HTTP 方法 HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null); Object body = NO_VALUE; // <4> 开始从请求中解析方法入参 EmptyBodyCheckingHttpInputMessage message; try { // <4.1> 将请求消息对象封装成 EmptyBodyCheckingHttpInputMessage,用于校验是否有请求体,没有的话设置为 `null` message = new EmptyBodyCheckingHttpInputMessage(inputMessage); // <4.2> 遍历 HttpMessageConverter for (HttpMessageConverter<?> converter : this.messageConverters) { Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass(); GenericHttpMessageConverter<?> genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); // 如果该 HttpMessageConverter 能够读取当前请求体解析出方法入参 if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) : (targetClass != null && converter.canRead(targetClass, contentType))) { // <4.2.1> 如果请求体不为空 if (message.hasBody()) { HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); // 通过该 HttpMessageConverter 从请求体中解析出方法入参对象 body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse)); // 调用 RequestResponseBodyAdvice 的 afterBodyRead 方法,存在 RequestBodyAdvice 则对方法入参进行修改 body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); } // <4.2.2> 如果请求体为空,则无需解析请求体 else { // 调用 RequestResponseBodyAdvice 的 afterBodyRead 方法,存在 RequestBodyAdvice 则对方法入参进行修改 body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType); } break; } } } catch (IOException ex) { throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage); } // <5> 校验解析出来的方法入参对象是否为空 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 + "]"; }); // <6> 返回方法入参对象 return body; } 我们直接看到父类 AbstractMessageConverterMethodArgumentResolver 的
方法虽然很长,但是不难理解,大致逻辑就是找到合适的 HttpMessageConverter 实现类从请求体中获取到方法入参对象 逻辑和下面的 |
|