RequestMappingHandlerAdapter详解()

  本篇文章为你整理了RequestMappingHandlerAdapter详解()的详细内容,包含有 RequestMappingHandlerAdapter详解,希望能帮助你了解 RequestMappingHandlerAdapter详解。

   RequestMappingHandlerAdapter是Spring Web MVC中针对@Controller和@RequestMapping体系的处理器适配器,本文对RequestMappingHandlerAdapter的组成、初始化以及同步请求处理流程进行详细梳理和总结。

  
 

  RequestMappingHandlerAdapter是日常项目中使用最多的HandlerAdapter实现类。

  它还有一个抽象父类AbstractHandlerMethodAdapter,顾名思义,是专门用来处理HandlerMethod类型的handler。具体可以看AbstractHandlerMethodAdapter#supports方法:

  

public final boolean supports(Object handler) { 

 

   return (handler instanceof HandlerMethod supportsInternal((HandlerMethod) handler));

  

 

  通过之前的学习可以知道,RequestMappingHandlerMapping获取的handler就是HandlerMethod类型的。

  RequestMappingHandlerMapping和RequestMappingHandlerAdapter就像一对孪生兄弟:

  RequestMappingHandlerMapping负责根据request找到映射的handler

  RequestMappingHandlerAdapter负责根据handler执行对应的方法

  我们先总结RequestMappingHandlerAdapter处理handler的核心流程:

  将request和response封装成ServletWebRequest对象。

  将handler封装成ServletInvocableHandlerMethod对象invocableMethod。

  为invocableMethod设置argumentResolvers、returnValueHandlers、dataBinderFactory和parameterNameDiscoverer等工具。

  解析请求参数。

  执行方法。

  处理返回值。

  实际上,RequestMappingHandlerAdapter处理handler过程中还有许多细节,比如前后端不分离项目的视图相关处理(没有必要花费时间深入学习),异步请求的相关处理(会另外写文章)。

  0 预备知识

  RequestMappingHandlerAdapter中有许多成员变量,在请求处理过程中起着重要的作用。

  0.1 argumentResolvers

  argumentResolvers是参数解析器,RequestMappingHandlerAdapter使用argumentResolvers进行参数解析。

  简单来说,就是将HTTP请求中的数据,转换成handler方法中的形参对象。

  argumentResolvers使用了组合模式,它的类型是HandlerMethodArgumentResolverComposite,其内部缓存HandlerMethodArgumentResolver对象,用来进行参数解析。

  HandlerMethodArgumentResolverComposite中包含argumentResolvers和argumentResolverCache两个成员变量。在初始化时,会将所有配置的参数解析器缓存到argumentResolvers中。第一次解析参数时,会遍历argumentResolvers获取对应参数解析器,并缓存到argumentResolverCache中,后续再次解析该参数可直接从键值对中获取,提高效率。

  实际进行参数解析的是HandlerMethodArgumentResolver实现类。它们使用了策略模式,通过supportsParameter()方法获取支持的参数解析器,通过resolveArgument()方法进行参数解析。

  0.2 customArgumentResolvers

  customArgumentResolvers是用于缓存开发人员自定义的参数解析器,即通过WebMvcConfigurer#addArgumentResolvers()方法添加的解析器。

  在RequestMappingHandlerAdapter初始化时,会将customArgumentResolvers中的自定义参数解析器添加到argumentResolvers中。

  0.3 returnValueHandlers

  returnValueHandlers是返回值处理器,它可以对控制层业务返回值进行处理。

  例如,对@ResponseBody标注的返回值进行JSON格式化,并写到输出流。

  returnValueHandlers使用了组合模式,它的类型是HandlerMethodReturnValueHandlerComposite,其内部缓存HandlerMethodReturnValueHandler对象,用来进行返回值处理。

  0.4 customReturnValueHandlers

  customReturnValueHandlers是用于缓存开发人员自定义的参数解析器,即通过WebMvcConfigurer#addReturnValueHandlers()方法添加的解析器。

  在RequestMappingHandlerAdapter初始化时,会将customReturnValueHandlers中的自定义参数解析器添加到returnValueHandlers中。

  1 初始化流程

  在RequestMappingHandlerAdapter内部,有两个方法用于初始化。一个是构造函数,另一个是实现org.springframework.beans.factory.InitializingBean的afterPropertiesSet()方法。

  在Spring Boot中,会在WebMvcConfigurationSupport中进行完整的初始化。

  1.1 构造函数

  构造函数中主要是对messageConverters进行初始化,添加一些必备的消息转换器。实际上,WebMvcConfigurationSupport中会进行覆盖,因此不过多描述:

  

public RequestMappingHandlerAdapter() { 

 

   this.messageConverters = new ArrayList (4);

   this.messageConverters.add(new ByteArrayHttpMessageConverter());

   this.messageConverters.add(new StringHttpMessageConverter());

   if (!shouldIgnoreXml) {

   try {

   this.messageConverters.add(new SourceHttpMessageConverter ());

   catch (Error err) {

   // Ignore when no TransformerFactory implementation is available

   this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

  

 

  1.2 afterPropertiesSet()

  在RequestMappingHandlerAdapter#afterPropertiesSet()方法中,会对argumentResolvers、initBinderArgumentResolvers和returnValueHandlers等进行初始化:

  

public void afterPropertiesSet() { 

 

   // Do this first, it may add ResponseBody advice beans

   initControllerAdviceCache();

   if (this.argumentResolvers == null) {

   List HandlerMethodArgumentResolver resolvers = getDefaultArgumentResolvers();

   this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);

   if (this.initBinderArgumentResolvers == null) {

   List HandlerMethodArgumentResolver resolvers = getDefaultInitBinderArgumentResolvers();

   this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);

   if (this.returnValueHandlers == null) {

   List HandlerMethodReturnValueHandler handlers = getDefaultReturnValueHandlers();

   this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);

  

 

  1.2.1 initControllerAdviceCache

  在RequestMappingHandlerAdapter#initControllerAdviceCache()方法中,会从容器中获取所有@ControllerAdvice标注的bean。然后缓存这些bean中标注@RequestMapping @ModelAttribute(modelAttributeAdviceCache)和@InitBinder(initBinderAdviceChache)等注解的方法,并且直接缓存实现RequestBodyAdvice或ResponseBodyAdvice的bean(requestResponseBodyAdvice)。

  

private void initControllerAdviceCache() { 

 

   if (getApplicationContext() == null) {

   return;

   List ControllerAdviceBean adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

   List Object requestResponseBodyAdviceBeans = new ArrayList ();

   for (ControllerAdviceBean adviceBean : adviceBeans) {

   Class ? beanType = adviceBean.getBeanType();

   if (beanType == null) {

   throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);

   Set Method attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);

   if (!attrMethods.isEmpty()) {

   this.modelAttributeAdviceCache.put(adviceBean, attrMethods);

   Set Method binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);

   if (!binderMethods.isEmpty()) {

   this.initBinderAdviceCache.put(adviceBean, binderMethods);

   if (RequestBodyAdvice.class.isAssignableFrom(beanType) ResponseBodyAdvice.class.isAssignableFrom(beanType)) {

   requestResponseBodyAdviceBeans.add(adviceBean);

   if (!requestResponseBodyAdviceBeans.isEmpty()) {

   this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);

  

 

  1.2.2 getDefaultXxx()方法

  通过getDefaultArgumentResolvers()、getDefaultInitBinderArgumentResolvers()和getDefaultResurnValueHandlers()方法分别对argumentResolvers、initBinderArgumentResolvers和returnValueHandlers进行初始化。

  在这些getDefaultXxx()方法中,一方面会按一定顺序添加一系列默认的处理器对象,另一方面会通过getCustomXxx()方法获取开发人员自定义的处理器对象(可通过WevMvcConfigurer添加)。

  例如,RequestMappingHandlerAdapter#getDefaultArgumentResolvers()方法会添加一系列默认的参数解析器,并且通过getCustomArgumentResolvers()方法获取开发人员自定义的参数解析器:

  

private List HandlerMethodArgumentResolver getDefaultArgumentResolvers() { 

 

   List HandlerMethodArgumentResolver resolvers = new ArrayList (30);

   // Annotation-based argument resolution

   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));

   resolvers.add(new RequestParamMapMethodArgumentResolver());

   resolvers.add(new PathVariableMethodArgumentResolver());

   resolvers.add(new PathVariableMapMethodArgumentResolver());

   resolvers.add(new MatrixVariableMethodArgumentResolver());

   resolvers.add(new MatrixVariableMapMethodArgumentResolver());

   resolvers.add(new ServletModelAttributeMethodProcessor(false));

   resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));

   resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));

   resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));

   resolvers.add(new RequestHeaderMapMethodArgumentResolver());

   resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));

   resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

   resolvers.add(new SessionAttributeMethodArgumentResolver());

   resolvers.add(new RequestAttributeMethodArgumentResolver());

   // Type-based argument resolution

   resolvers.add(new ServletRequestMethodArgumentResolver());

   resolvers.add(new ServletResponseMethodArgumentResolver());

   resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));

   resolvers.add(new RedirectAttributesMethodArgumentResolver());

   resolvers.add(new ModelMethodProcessor());

   resolvers.add(new MapMethodProcessor());

   resolvers.add(new ErrorsMethodArgumentResolver());

   resolvers.add(new SessionStatusMethodArgumentResolver());

   resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

   if (KotlinDetector.isKotlinPresent()) {

   resolvers.add(new ContinuationHandlerMethodArgumentResolver());

   // Custom arguments

   if (getCustomArgumentResolvers() != null) {

   resolvers.addAll(getCustomArgumentResolvers());

   // Catch-all

   resolvers.add(new PrincipalMethodArgumentResolver());

   resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));

   resolvers.add(new ServletModelAttributeMethodProcessor(true));

   return resolvers;

  

 

  1.3 WebMvcConfigurationSupport

  在WebMvcConfigurationSupport#requestMappingHandlerAdapter()中,会完成requestMappingHandlerAdapter的bean的创建,对contentNegotiationManager、messageConverters、webBindingInitializer、customArgumentResolvers和customReturnValueHandlers等基础成员变量,以及异步请求的taskExecutor、asyncRequestTimeout、callableInterceptors和deferredResultInterceptors等成员变量进行初始化:

  

public RequestMappingHandlerAdapter requestMappingHandlerAdapter( 

 

   @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,

   @Qualifier("mvcConversionService") FormattingConversionService conversionService,

   @Qualifier("mvcValidator") Validator validator) {

   RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();

   adapter.setContentNegotiationManager(contentNegotiationManager);

   adapter.setMessageConverters(getMessageConverters());

   adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));

   adapter.setCustomArgumentResolvers(getArgumentResolvers());

   adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

   if (jackson2Present) {

   adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));

   adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));

   AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();

   if (configurer.getTaskExecutor() != null) {

   adapter.setTaskExecutor(configurer.getTaskExecutor());

   if (configurer.getTimeout() != null) {

   adapter.setAsyncRequestTimeout(configurer.getTimeout());

   adapter.setCallableInterceptors(configurer.getCallableInterceptors());

   adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

   return adapter;

  

 

  在初始化过程中,一方面会为这些成员添加一系列默认对象,另一方面会从WebMvcConfigurer中获取开发人员自定义的对象。

  2 同步请求处理流程

  首先,DispatcherServlet会调用HandlerAdapter接口的handle()方法。

  AbstractHandlerMethodAdapter对handle()方法的实现只是做了一个类型转换:

  

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 

 

   throws Exception {

   return handleInternal(request, response, (HandlerMethod) handler);

  

 

  AbstractHandlerMethodAdapter#handleInternal()是一个抽象方法,会由子类具体去实现。

  RequestMappingHandlerAdapter#handlerInternal()方法中会进行一些请求判断和缓存处理(省略),它的核心是在invokeHandlerMethod()方法:

  

protected ModelAndView handleInternal(HttpServletRequest request, 

 

   HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;

   mav = invokeHandlerMethod(request, response, handlerMethod);

   return mav;

  

 

  2.1 预处理:添加处理器

  在RequestMappingHandlerAdapter#invokeHandlerMethod()方法中,会进行如下处理:

  将request和response封装成ServletWebRequest对象,便于后续处理。

  将handler封装成ServletInvocableHandlerMethod对象invocableMethod。

  为invocableMethod设置argumentResolvers(参数解析)、returnValueHandlers(返回值处理)、dataBinderFactory(数据绑定和校验)和parameterNameDiscoverer(形参名字解析)等组件,用作后续方法处理的工具。这些组件都来自RequestMappingHandlerAdapter的成员变量。

  最后会调用invocableMethod的invokeAndHandle()方法进行实际处理。

  RequestMappingHandlerAdapter#invokeHandlerMethod()具体源码如下:

  

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, 

 

   HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   // 1、将`request`和`response`封装成`ServletWebRequest`对象

   ServletWebRequest webRequest = new ServletWebRequest(request, response);

   try {

   WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

   ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

   // 2、将`handler`封装成`ServletInvocableHandlerMethod`对象`invocableMethod`

   ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);

   // 3、为`invocableMethod`设置`argumentResolvers`、`returnValueHandlers`、`dataBinderFactory`和`parameterNameDiscoverer`等工具

   if (this.argumentResolvers != null) {

   invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);

   if (this.returnValueHandlers != null) {

   invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);

   invocableMethod.setDataBinderFactory(binderFactory);

   invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

   // 4、处理请求

   invocableMethod.invokeAndHandle(webRequest, mavContainer);

   return getModelAndView(mavContainer, modelFactory, webRequest);

   finally {

   webRequest.requestCompleted();

  

 

  ServletInvocableHandlerMethod#invokeAndHandle()方法会调用请求,并且对返回值进行处理:

  

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { 

 

   // 1、调用请求

   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

   // 省略相关代码

   // 2、返回值处理

   try {

   this.returnValueHandlers.handleReturnValue(

   returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

   catch (Exception ex) {

   if (logger.isTraceEnabled()) {

   logger.trace(formatErrorForReturnValue(returnValue), ex);

   throw ex;

  

 

  2.2 形参对象解析

  在InvocableHandlerMethod#invokeForRequest()方法中,会进行参数解析(将request中的数据解析成handler方法的形参对象),然后通过反射调用对应方法,获取返回值:

  

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { 

 

   // 1、参数解析

   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

   // 2、调用方法

   return doInvoke(args);

  

 

  在InvocableHandlerMethod#getMethodArgumentValues()方法中,会通过反射获取handler方法的形参,然后使用resolvers对一个个形参进行解析。

  根据形参的类型不同(HttpServletRequest等),形参上标注的注解不同(@RequestBody等),会调用不同的解析器实现类进行处理。

  根据解析器实现类的不同,在解析过程中,会进行数据绑定、消息转换和参数校验:

  

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { 

 

   // 1、获取方法的形参信息

   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 {

   // 2、形参解析

   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;

  

 

  2.3 执行方法

  回到InvocableHandlerMethod#invokeForRequest()方法,解析方法形参后,会调用InvocableHandlerMethod#doInvoke()方法,通过反射调用方法,并传入handler对应的控制层bean作为触发对象,以及上述形参对象:

  

protected Object doInvoke(Object... args) throws Exception { 

 

   Method method = getBridgedMethod();

   try {

   return method.invoke(getBean(), args);

   catch (IllegalArgumentException ex) {

   // 省略相关代码

  

 

  2.4 返回值处理

  回到ServletInvocableHandlerMethod#invokeAndHandle()方法,此时获取了handler方法执行完成的返回值,会调用HandlerMethodReturnValueHandlerComposite#handleReturnValue()方法对返回值进行处理。首先会根据返回值信息MethodParameter对象查找支持的返回值处理器HandlerMethodReturnValueHandler,然后使用该处理器对返回值进行处理:

  

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, 

 

   ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

   // 1、查找返回值处理器

   HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);

   // 2、返回值处理

   handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

  

 

  在HandlerMethodReturnValueHandlerComposite#selectHandler方法中,会遍历returnValueHandlers,调用其HandlerMethodReturnValueHandler#supportsReturnType实现方法找到对应返回值处理器。:

  

private HandlerMethodReturnValueHandler selectHandler(@Nullable 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;

  

 

  找到返回值处理器后,就可以通过其handleReturnValue()方法对返回值进行处理。

  举个有实战意义的例子,@ResponseBody的HandlerMethodReturnValueHandler实现类是RequestResponseBodyMethodProcessor。

  RequestResponseBodyMethodProcessor的supportsReturnType()方法会判断返回值是否标有ResponseBody注解:

  

public boolean supportsReturnType(MethodParameter returnType) { 

 

   return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class)

   returnType.hasMethodAnnotation(ResponseBody.class));

  

 

  RequestResponseBodyMethodProcessor的handleReturnValue()方法会根据返回的Content-Type对返回值进行对应格式化,并写入到输出流中:

  

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

   // Try even with null return value. ResponseBodyAdvice could get involved.

   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);

  

 

  至此,我们走完了RequestMappingHandlerAdapter对同步请求的完整处理流程(前后端分离)。简单来说,会经过一下主要步骤:

  初始化请求处理的工具:argumentResolvers、returnValueHandlers、binderFactory和parameterNameDiscoverer等。

  解析形参对象

  返回值处理

  实际上RequestMappingHandlerAdapter中还会对异步请求进行处理,这部分我们会在之后的文章进行详细介绍。

  3 HandlerMethodArgumentResolver实现类

  3.1 RequestResponseBodyMethodProcessor

  RequestResponseBodyMethodProcessor是前后端分离项目中使用最多的HandlerMethodArgumentResolver实现类,它可以处理@RequestBody标注的形参。

  3.1.1 supportsParameter()方法

  RequestResponseBodyMethodProcessor#supportsParameter()方法会判断形参上是否标注@RequestBody注解:

  

public boolean supportsParameter(MethodParameter parameter) { 

 

   return parameter.hasParameterAnnotation(RequestBody.class);

  

 

  3.1.2 resolveArgument()方法

  RequestResponseBodyMethodProcessor#resolveArgument()方法会从输入流中读取数据,转换成形参对象,并且对其进行数据校验:

  

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

   return adaptArgumentIfNecessary(arg, parameter);

  

 

  AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters()方法会根据Content-Type从输入流读取数据,并创建成形参对象:

  

protected T Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, 

 

   Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

   // 获取请求Content-Type

   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;

   // 根据Content-Type使用对应messageConverter读取并转换数据

   EmptyBodyCheckingHttpInputMessage message = null;

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

   // 根据Content-Type获取对应的messageConverter

   if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :

   (targetClass != null converter.canRead(targetClass, contentType))) {

   if (message.hasBody()) {

   // RequestBodyAdvice#beforeBodyRead()处理

   HttpInputMessage msgToUse =

   getAdvice().beforeBodyRead(message, parameter, targetType, converterType);

   // 读取并转换数据

   body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :

   ((HttpMessageConverter T ) converter).read(targetClass, msgToUse));

   // RequestBodyAdvice#afterBodyRead()处理

   body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);

   else {

   body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);

   break;

   catch (IOException ex) {

   throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);

   finally {

   if (message != null message.hasBody()) {

   closeStreamIfNecessary(message.getBody());

   if (body == NO_VALUE) {

   if (httpMethod == null !SUPPORTED_METHODS.contains(httpMethod)

   (noContentType !message.hasBody())) {

   return null;

   throw new HttpMediaTypeNotSupportedException(contentType,

   getSupportedMediaTypes(targetClass != null ? targetClass : Object.class));

   MediaType selectedContentType = contentType;

   Object theBody = body;

   LogFormatUtils.traceDebug(logger, traceOn - {

   String formatted = LogFormatUtils.formatValue(theBody, !traceOn);

   return "Read \"" + selectedContentType + "\" to [" + formatted + "]";

   });

   return body;

  

 

  AbstractMessageConverterMethodArgumentResolver#validateIfApplicable()方法会对标注javax.validation.Valid、org.springframework.validation.annotation.Validated以及以Valid开头的自定义注解进行参数校验:

  

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { 

 

   Annotation[] annotations = parameter.getParameterAnnotations();

   for (Annotation ann : annotations) {

   Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);

   if (validationHints != null) {

   binder.validate(validationHints);

   break;

  

 

  4 HandlerMethodReturnValueHandler实现类

  4.1 RequestResponseBodyMethodProcessor

  RequestResponseBodyMethodProcessor是前后端分离项目中使用最多的HandlerMethodReturnValueHandler实现类,它可以处理@ResponseBody标注的返回值。

  4.1.1 supportsReturnType()方法

  RequestResponseBodyMethodProcessor#supportsReturnType()方法会判断类或方法上是否标注@RequestBody注解:

  

public boolean supportsReturnType(MethodParameter returnType) { 

 

   return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class)

   returnType.hasMethodAnnotation(ResponseBody.class));

  

 

  4.1.2 handleReturnValue()方法

  RequestResponseBodyMethodProcessor#handleReturnValue()方法会根据响应的Content-Type,将返回值格式化成对应数据格式,写道输出流进行响应:

  

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

   // Try even with null return value. ResponseBodyAdvice could get involved.

   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);

  

 

  实际业务在AbstractMessageConverterMethodProcessor#writeWithMessageConverters()方法,

  

protected T void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, 

 

   ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)

   throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

   Object body;

   Class ? valueType;

   Type targetType;

   // 如果返回值是CharSequence类型,valueType和targetType都设置成String类型

   if (value instanceof CharSequence) {

   body = value.toString();

   valueType = String.class;

   targetType = String.class;

   // 如果返回值不是CharSequence,valueType设置成对应返回值类。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: