RequestMappingHandlerAdapter详解

[复制链接]
发表于 2023-1-1 23:49:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

RequestMappingHandlerAdapter是日常项目中使用最多的HandlerAdapter实现类。
它还有一个抽象父类AbstractHandlerMethodAdapter,顾名思义,是专门用来处理HandlerMethod类型的handler。具体可以看AbstractHandlerMethodAdapter#supports方法:
  1. public final boolean supports(Object handler) {  
  2.    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));  
  3. }
复制代码
通过之前的学习可以知道,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中会进行覆盖,因此不过多描述:
  1. public RequestMappingHandlerAdapter() {  
  2.    this.messageConverters = new ArrayList<>(4);  
  3.    this.messageConverters.add(new ByteArrayHttpMessageConverter());  
  4.    this.messageConverters.add(new StringHttpMessageConverter());  
  5.    if (!shouldIgnoreXml) {  
  6.       try {  
  7.          this.messageConverters.add(new SourceHttpMessageConverter<>());  
  8.       }  
  9.       catch (Error err) {  
  10.          // Ignore when no TransformerFactory implementation is available  
  11.       }  
  12.    }  
  13.    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());  
  14. }
复制代码
1.2 afterPropertiesSet()

在RequestMappingHandlerAdapter#afterPropertiesSet()方法中,会对argumentResolvers、initBinderArgumentResolvers和returnValueHandlers等进行初始化:
  1. public void afterPropertiesSet() {  
  2.    // Do this first, it may add ResponseBody advice beans  
  3.    initControllerAdviceCache();  
  4.   
  5.    if (this.argumentResolvers == null) {  
  6.       List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();  
  7.       this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);  
  8.    }  
  9.    if (this.initBinderArgumentResolvers == null) {  
  10.       List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();  
  11.       this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);  
  12.    }  
  13.    if (this.returnValueHandlers == null) {  
  14.       List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();  
  15.       this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);  
  16.    }  
  17. }
复制代码
1.2.1 initControllerAdviceCache

在RequestMappingHandlerAdapter#initControllerAdviceCache()方法中,会从容器中获取所有@ControllerAdvice标注的bean。然后缓存这些bean中标注@RequestMapping&@ModelAttribute(modelAttributeAdviceCache)和@InitBinder(initBinderAdviceChache)等注解的方法,并且直接缓存实现RequestBodyAdvice或ResponseBodyAdvice的bean(requestResponseBodyAdvice)。
  1. private void initControllerAdviceCache() {  
  2.    if (getApplicationContext() == null) {  
  3.       return;  
  4.    }  
  5.   
  6.    List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());  
  7.   
  8.    List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();  
  9.   
  10.    for (ControllerAdviceBean adviceBean : adviceBeans) {  
  11.       Class<?> beanType = adviceBean.getBeanType();  
  12.       if (beanType == null) {  
  13.          throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);  
  14.       }  
  15.       Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);  
  16.       if (!attrMethods.isEmpty()) {  
  17.          this.modelAttributeAdviceCache.put(adviceBean, attrMethods);  
  18.       }  
  19.       Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);  
  20.       if (!binderMethods.isEmpty()) {  
  21.          this.initBinderAdviceCache.put(adviceBean, binderMethods);  
  22.       }  
  23.       if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {  
  24.          requestResponseBodyAdviceBeans.add(adviceBean);  
  25.       }  
  26.    }  
  27.   
  28.    if (!requestResponseBodyAdviceBeans.isEmpty()) {  
  29.       this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);  
  30.    }  
  31. }
复制代码
1.2.2 getDefaultXxx()方法

通过getDefaultArgumentResolvers()、getDefaultInitBinderArgumentResolvers()和getDefaultResurnValueHandlers()方法分别对argumentResolvers、initBinderArgumentResolvers和returnValueHandlers进行初始化。
在这些getDefaultXxx()方法中,一方面会按一定顺序添加一系列默认的处理器对象,另一方面会通过getCustomXxx()方法获取开发人员自定义的处理器对象(可通过WevMvcConfigurer添加)。
例如,RequestMappingHandlerAdapter#getDefaultArgumentResolvers()方法会添加一系列默认的参数解析器,并且通过getCustomArgumentResolvers()方法获取开发人员自定义的参数解析器:
  1. private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {  
  2.    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);  
  3.   
  4.    // Annotation-based argument resolution  
  5.    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));  
  6.    resolvers.add(new RequestParamMapMethodArgumentResolver());  
  7.    resolvers.add(new PathVariableMethodArgumentResolver());  
  8.    resolvers.add(new PathVariableMapMethodArgumentResolver());  
  9.    resolvers.add(new MatrixVariableMethodArgumentResolver());  
  10.    resolvers.add(new MatrixVariableMapMethodArgumentResolver());  
  11.    resolvers.add(new ServletModelAttributeMethodProcessor(false));  
  12.    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));  
  13.    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));  
  14.    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));  
  15.    resolvers.add(new RequestHeaderMapMethodArgumentResolver());  
  16.    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));  
  17.    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));  
  18.    resolvers.add(new SessionAttributeMethodArgumentResolver());  
  19.    resolvers.add(new RequestAttributeMethodArgumentResolver());  
  20.   
  21.    // Type-based argument resolution  
  22.    resolvers.add(new ServletRequestMethodArgumentResolver());  
  23.    resolvers.add(new ServletResponseMethodArgumentResolver());  
  24.    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));  
  25.    resolvers.add(new RedirectAttributesMethodArgumentResolver());  
  26.    resolvers.add(new ModelMethodProcessor());  
  27.    resolvers.add(new MapMethodProcessor());  
  28.    resolvers.add(new ErrorsMethodArgumentResolver());  
  29.    resolvers.add(new SessionStatusMethodArgumentResolver());  
  30.    resolvers.add(new UriComponentsBuilderMethodArgumentResolver());  
  31.    if (KotlinDetector.isKotlinPresent()) {  
  32.       resolvers.add(new ContinuationHandlerMethodArgumentResolver());  
  33.    }  
  34.   
  35.    // Custom arguments  
  36.    if (getCustomArgumentResolvers() != null) {  
  37.       resolvers.addAll(getCustomArgumentResolvers());  
  38.    }  
  39.   
  40.    // Catch-all  
  41.    resolvers.add(new PrincipalMethodArgumentResolver());  
  42.    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));  
  43.    resolvers.add(new ServletModelAttributeMethodProcessor(true));  
  44.   
  45.    return resolvers;
复制代码
1.3 WebMvcConfigurationSupport

在WebMvcConfigurationSupport#requestMappingHandlerAdapter()中,会完成requestMappingHandlerAdapter的bean的创建,对contentNegotiationManager、messageConverters、webBindingInitializer、customArgumentResolvers和customReturnValueHandlers等基础成员变量,以及异步请求的taskExecutor、asyncRequestTimeout、callableInterceptors和deferredResultInterceptors等成员变量进行初始化:
  1. public RequestMappingHandlerAdapter requestMappingHandlerAdapter(  
  2.       @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,  
  3.       @Qualifier("mvcConversionService") FormattingConversionService conversionService,  
  4.       @Qualifier("mvcValidator") Validator validator) {  
  5.   
  6.    RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();  
  7.    adapter.setContentNegotiationManager(contentNegotiationManager);  
  8.    adapter.setMessageConverters(getMessageConverters());  
  9.    adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));  
  10.    adapter.setCustomArgumentResolvers(getArgumentResolvers());  
  11.    adapter.setCustomReturnValueHandlers(getReturnValueHandlers());  
  12.   
  13.    if (jackson2Present) {  
  14.       adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));  
  15.       adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));  
  16.    }  
  17.   
  18.    AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();  
  19.    if (configurer.getTaskExecutor() != null) {  
  20.       adapter.setTaskExecutor(configurer.getTaskExecutor());  
  21.    }  
  22.    if (configurer.getTimeout() != null) {  
  23.       adapter.setAsyncRequestTimeout(configurer.getTimeout());  
  24.    }  
  25.    adapter.setCallableInterceptors(configurer.getCallableInterceptors());  
  26.    adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());  
  27.   
  28.    return adapter;  
  29. }
复制代码
在初始化过程中,一方面会为这些成员添加一系列默认对象,另一方面会从WebMvcConfigurer中获取开发人员自定义的对象。
2 同步请求处理流程

首先,DispatcherServlet会调用HandlerAdapter接口的handle()方法。
AbstractHandlerMethodAdapter对handle()方法的实现只是做了一个类型转换:
  1. public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)  
  2.       throws Exception {  
  3.    return handleInternal(request, response, (HandlerMethod) handler);  
  4. }
复制代码
AbstractHandlerMethodAdapter#handleInternal()是一个抽象方法,会由子类具体去实现。
RequestMappingHandlerAdapter#handlerInternal()方法中会进行一些请求判断和缓存处理(省略),它的核心是在invokeHandlerMethod()方法:
  1. protected ModelAndView handleInternal(HttpServletRequest request,  
  2.       HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {  
  3.   
  4.    ModelAndView mav;  
  5.    
  6.    mav = invokeHandlerMethod(request, response, handlerMethod);
  7.   
  8.    return mav;  
  9. }
复制代码
2.1 预处理:添加处理器

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

  • 将request和response封装成ServletWebRequest对象,便于后续处理。
  • 将handler封装成ServletInvocableHandlerMethod对象invocableMethod。
  • 为invocableMethod设置argumentResolvers(参数解析)、returnValueHandlers(返回值处理)、dataBinderFactory(数据绑定和校验)和parameterNameDiscoverer(形参名字解析)等组件,用作后续方法处理的工具。这些组件都来自RequestMappingHandlerAdapter的成员变量。
  • 最后会调用invocableMethod的invokeAndHandle()方法进行实际处理。
RequestMappingHandlerAdapter#invokeHandlerMethod()具体源码如下:
  1. protected ModelAndView invokeHandlerMethod(HttpServletRequest request,  
  2.       HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  3.    // 1、将`request`和`response`封装成`ServletWebRequest`对象
  4.    ServletWebRequest webRequest = new ServletWebRequest(request, response);  
  5.    try {  
  6.       WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);  
  7.       ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
  8.       // 2、将`handler`封装成`ServletInvocableHandlerMethod`对象`invocableMethod`
  9.       ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);  
  10.       // 3、为`invocableMethod`设置`argumentResolvers`、`returnValueHandlers`、`dataBinderFactory`和`parameterNameDiscoverer`等工具
  11.       if (this.argumentResolvers != null) {  
  12.          invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);  
  13.       }  
  14.       if (this.returnValueHandlers != null) {  
  15.          invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);  
  16.       }  
  17.       invocableMethod.setDataBinderFactory(binderFactory);  
  18.       invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);  
  19.       // 4、处理请求
  20.       invocableMethod.invokeAndHandle(webRequest, mavContainer);   
  21.       return getModelAndView(mavContainer, modelFactory, webRequest);  
  22.    }  
  23.    finally {  
  24.       webRequest.requestCompleted();  
  25.    }  
  26. }
复制代码
ServletInvocableHandlerMethod#invokeAndHandle()方法会调用请求,并且对返回值进行处理:
  1. public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  
  2.    // 1、调用请求
  3.    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);  
  4.    // 省略相关代码
  5.    // 2、返回值处理
  6.    try {  
  7.       this.returnValueHandlers.handleReturnValue(  
  8.             returnValue, getReturnValueType(returnValue), mavContainer, webRequest);  
  9.    }  
  10.    catch (Exception ex) {  
  11.       if (logger.isTraceEnabled()) {  
  12.          logger.trace(formatErrorForReturnValue(returnValue), ex);  
  13.       }  
  14.       throw ex;  
  15.    }  
  16. }
复制代码
2.2 形参对象解析

在InvocableHandlerMethod#invokeForRequest()方法中,会进行参数解析(将request中的数据解析成handler方法的形参对象),然后通过反射调用对应方法,获取返回值:
  1. public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  
  2.    // 1、参数解析
  3.    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);  
  4.    // 2、调用方法
  5.    return doInvoke(args);  
  6. }
复制代码
在InvocableHandlerMethod#getMethodArgumentValues()方法中,会通过反射获取handler方法的形参,然后使用resolvers对一个个形参进行解析。
根据形参的类型不同(HttpServletRequest等),形参上标注的注解不同(@RequestBody等),会调用不同的解析器实现类进行处理。
根据解析器实现类的不同,在解析过程中,会进行数据绑定、消息转换和参数校验:
  1. protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {  
  2.    // 1、获取方法的形参信息
  3.    MethodParameter[] parameters = getMethodParameters();  
  4.    if (ObjectUtils.isEmpty(parameters)) {  
  5.       return EMPTY_ARGS;  
  6.    }  
  7.   
  8.    Object[] args = new Object[parameters.length];  
  9.    // 遍历方法形参
  10.    for (int i = 0; i < parameters.length; i++) {  
  11.       MethodParameter parameter = parameters[i];  
  12.       parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);  
  13.       args[i] = findProvidedArgument(parameter, providedArgs);  
  14.       if (args[i] != null) {  
  15.          continue;  
  16.       }  
  17.       if (!this.resolvers.supportsParameter(parameter)) {  
  18.          throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));  
  19.       }  
  20.       try {  
  21.          // 2、形参解析
  22.          args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);  
  23.       }  
  24.       catch (Exception ex) {  
  25.          // Leave stack trace for later, exception may actually be resolved and handled...  
  26.          if (logger.isDebugEnabled()) {  
  27.             String exMsg = ex.getMessage();  
  28.             if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {  
  29.                logger.debug(formatArgumentError(parameter, exMsg));  
  30.             }  
  31.          }  
  32.          throw ex;  
  33.       }  
  34.    }  
  35.    return args;  
  36. }
复制代码
2.3 执行方法

回到InvocableHandlerMethod#invokeForRequest()方法,解析方法形参后,会调用InvocableHandlerMethod#doInvoke()方法,通过反射调用方法,并传入handler对应的控制层bean作为触发对象,以及上述形参对象:
  1. protected Object doInvoke(Object... args) throws Exception {  
  2.    Method method = getBridgedMethod();  
  3.    try {  
  4.       return method.invoke(getBean(), args);  
  5.    }  
  6.    catch (IllegalArgumentException ex) {  
  7.       // 省略相关代码
  8.    }  
  9. }
复制代码
2.4 返回值处理

回到ServletInvocableHandlerMethod#invokeAndHandle()方法,此时获取了handler方法执行完成的返回值,会调用HandlerMethodReturnValueHandlerComposite#handleReturnValue()方法对返回值进行处理。首先会根据返回值信息MethodParameter对象查找支持的返回值处理器HandlerMethodReturnValueHandler,然后使用该处理器对返回值进行处理:
  1. public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,  
  2.       ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {  
  3.    // 1、查找返回值处理器
  4.    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);  
  5.    // 2、返回值处理
  6.    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);  
  7. }
复制代码
在HandlerMethodReturnValueHandlerComposite#selectHandler方法中,会遍历returnValueHandlers,调用其HandlerMethodReturnValueHandler#supportsReturnType实现方法找到对应返回值处理器。:
  1. private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {  
  2.    boolean isAsyncValue = isAsyncReturnValue(value, returnType);  
  3.    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {  
  4.       if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {  
  5.          continue;  
  6.       }  
  7.       if (handler.supportsReturnType(returnType)) {  
  8.          return handler;  
  9.       }  
  10.    }  
  11.    return null;  
  12. }
复制代码
找到返回值处理器后,就可以通过其handleReturnValue()方法对返回值进行处理。
举个有实战意义的例子,@ResponseBody的HandlerMethodReturnValueHandler实现类是RequestResponseBodyMethodProcessor。
RequestResponseBodyMethodProcessor的supportsReturnType()方法会判断返回值是否标有ResponseBody注解:
  1. public boolean supportsReturnType(MethodParameter returnType) {  
  2.    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||  
  3.          returnType.hasMethodAnnotation(ResponseBody.class));  
  4. }
复制代码
RequestResponseBodyMethodProcessor的handleReturnValue()方法会根据返回的Content-Type对返回值进行对应格式化,并写入到输出流中:
  1. public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,  
  2.       ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  
  3.       throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {  
  4.   
  5.    mavContainer.setRequestHandled(true);  
  6.    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);  
  7.    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);  
  8.   
  9.    // Try even with null return value. ResponseBodyAdvice could get involved.  
  10.    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);  
  11. }
复制代码
至此,我们走完了RequestMappingHandlerAdapter对同步请求的完整处理流程(前后端分离)。简单来说,会经过一下主要步骤:

  • 初始化请求处理的工具:argumentResolvers、returnValueHandlers、binderFactory和parameterNameDiscoverer等。
  • 解析形参对象
  • 执行方法
  • 返回值处理
实际上RequestMappingHandlerAdapter中还会对异步请求进行处理,这部分我们会在之后的文章进行详细介绍。
3 HandlerMethodArgumentResolver实现类

3.1 RequestResponseBodyMethodProcessor

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

RequestResponseBodyMethodProcessor#supportsParameter()方法会判断形参上是否标注@RequestBody注解:
  1. public boolean supportsParameter(MethodParameter parameter) {  
  2.    return parameter.hasParameterAnnotation(RequestBody.class);  
  3. }
复制代码
3.1.2 resolveArgument()方法

RequestResponseBodyMethodProcessor#resolveArgument()方法会从输入流中读取数据,转换成形参对象,并且对其进行数据校验:
  1. public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,  
  2.       NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {  
  3.   
  4.    parameter = parameter.nestedIfOptional();  
  5.    // 从输入流中读取数据,并构造成形参对象
  6.    Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());  
  7.    String name = Conventions.getVariableNameForParameter(parameter);  
  8.   
  9.    if (binderFactory != null) {  
  10.       WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);  
  11.       if (arg != null) {  
  12.          // 数据校验
  13.          validateIfApplicable(binder, parameter);  
  14.          if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {  
  15.             throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());  
  16.          }  
  17.       }  
  18.       if (mavContainer != null) {  
  19.          mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());  
  20.       }  
  21.    }  
  22.   
  23.    return adaptArgumentIfNecessary(arg, parameter);  
  24. }
复制代码
AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters()方法会根据Content-Type从输入流读取数据,并创建成形参对象:
  1. protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,  
  2.       Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {  
  3.   
  4.    // 获取请求Content-Type
  5.    MediaType contentType;  
  6.    boolean noContentType = false;  
  7.    try {  
  8.       contentType = inputMessage.getHeaders().getContentType();  
  9.    }  
  10.    catch (InvalidMediaTypeException ex) {  
  11.       throw new HttpMediaTypeNotSupportedException(ex.getMessage());  
  12.    }  
  13.    if (contentType == null) {  
  14.       noContentType = true;  
  15.       contentType = MediaType.APPLICATION_OCTET_STREAM;  
  16.    }  
  17.   
  18.    // 获取形参类型
  19.    Class<?> contextClass = parameter.getContainingClass();  
  20.    Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);  
  21.    if (targetClass == null) {  
  22.       ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);  
  23.       targetClass = (Class<T>) resolvableType.resolve();  
  24.    }  
  25.   
  26.    HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);  
  27.    Object body = NO_VALUE;  
  28.   
  29.    // 根据Content-Type使用对应messageConverter读取并转换数据
  30.    EmptyBodyCheckingHttpInputMessage message = null;  
  31.    try {  
  32.       message = new EmptyBodyCheckingHttpInputMessage(inputMessage);  
  33.   
  34.       for (HttpMessageConverter<?> converter : this.messageConverters) {  
  35.          Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();  
  36.          GenericHttpMessageConverter<?> genericConverter =  
  37.                (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);  
  38.          // 根据Content-Type获取对应的messageConverter
  39.          if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :  
  40.                (targetClass != null && converter.canRead(targetClass, contentType))) {  
  41.             if (message.hasBody()) {  
  42.                // RequestBodyAdvice#beforeBodyRead()处理
  43.                HttpInputMessage msgToUse =  
  44.                      getAdvice().beforeBodyRead(message, parameter, targetType, converterType);  
  45.                // 读取并转换数据
  46.                body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :  
  47.                      ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));  
  48.                // RequestBodyAdvice#afterBodyRead()处理
  49.                body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);  
  50.             }  
  51.             else {  
  52.                body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);  
  53.             }  
  54.             break;  
  55.          }  
  56.       }  
  57.    }  
  58.    catch (IOException ex) {  
  59.       throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);  
  60.    }  
  61.    finally {  
  62.       if (message != null && message.hasBody()) {  
  63.          closeStreamIfNecessary(message.getBody());  
  64.       }  
  65.    }  
  66.   
  67.    if (body == NO_VALUE) {  
  68.       if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||  
  69.             (noContentType && !message.hasBody())) {  
  70.          return null;  
  71.       }  
  72.       throw new HttpMediaTypeNotSupportedException(contentType,  
  73.             getSupportedMediaTypes(targetClass != null ? targetClass : Object.class));  
  74.    }  
  75.   
  76.    MediaType selectedContentType = contentType;  
  77.    Object theBody = body;  
  78.    LogFormatUtils.traceDebug(logger, traceOn -> {  
  79.       String formatted = LogFormatUtils.formatValue(theBody, !traceOn);  
  80.       return "Read "" + selectedContentType + "" to [" + formatted + "]";  
  81.    });  
  82.   
  83.    return body;  
  84. }
复制代码
AbstractMessageConverterMethodArgumentResolver#validateIfApplicable()方法会对标注javax.validation.Valid、org.springframework.validation.annotation.Validated以及以Valid开头的自定义注解进行参数校验:
  1. protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {  
  2.    Annotation[] annotations = parameter.getParameterAnnotations();  
  3.    for (Annotation ann : annotations) {  
  4.       Object[] validationHints = ValidationAnnotationUtils.determineValidationHints(ann);  
  5.       if (validationHints != null) {  
  6.          binder.validate(validationHints);  
  7.          break;  
  8.       }  
  9.    }  
  10. }
复制代码
4 HandlerMethodReturnValueHandler实现类

4.1 RequestResponseBodyMethodProcessor

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

RequestResponseBodyMethodProcessor#supportsReturnType()方法会判断类或方法上是否标注@RequestBody注解:
  1. public boolean supportsReturnType(MethodParameter returnType) {  
  2.    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||  
  3.          returnType.hasMethodAnnotation(ResponseBody.class));  
  4. }
复制代码
4.1.2 handleReturnValue()方法

RequestResponseBodyMethodProcessor#handleReturnValue()方法会根据响应的Content-Type,将返回值格式化成对应数据格式,写道输出流进行响应:
  1. public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,  
  2.       ModelAndViewContainer mavContainer, NativeWebRequest webRequest)  
  3.       throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {  
  4.   
  5.    mavContainer.setRequestHandled(true);  
  6.    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);  
  7.    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);  
  8.   
  9.    // Try even with null return value. ResponseBodyAdvice could get involved.  
  10.    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);  
  11. }
复制代码
实际业务在AbstractMessageConverterMethodProcessor#writeWithMessageConverters()方法,
  1. protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,  
  2.       ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)  
  3.       throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {  
  4.   
  5.    Object body;  
  6.    Class<?> valueType;  
  7.    Type targetType;  
  8.   
  9.    // 如果返回值是CharSequence类型,valueType和targetType都设置成String类型
  10.    if (value instanceof CharSequence) {  
  11.       body = value.toString();  
  12.       valueType = String.class;  
  13.       targetType = String.class;  
  14.    }  
  15.    // 如果返回值不是CharSequence,valueType设置成对应返回值类型,targetType会设置成解析泛型后的返回值类型
  16.    else {  
  17.       body = value;  
  18.       valueType = getReturnValueType(body, returnType);  
  19.       targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());  
  20.    }  
  21.    // 如果是返回值继承自Resource
  22.    if (isResourceType(value, returnType)) {  
  23.       outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");  
  24.       if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&  
  25.             outputMessage.getServletResponse().getStatus() == 200) {  
  26.          Resource resource = (Resource) value;  
  27.          try {  
  28.             List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();  
  29.             outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());  
  30.             body = HttpRange.toResourceRegions(httpRanges, resource);  
  31.             valueType = body.getClass();  
  32.             targetType = RESOURCE_REGION_LIST_TYPE;  
  33.          }  
  34.          catch (IllegalArgumentException ex) {  
  35.             outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());  
  36.             outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());  
  37.          }  
  38.       }  
  39.    }  
  40.   
  41.    // 获取响应的Content-Type
  42.    MediaType selectedMediaType = null;  
  43.    MediaType contentType = outputMessage.getHeaders().getContentType();  
  44.    boolean isContentTypePreset = contentType != null && contentType.isConcrete();  
  45.    if (isContentTypePreset) {  
  46.       if (logger.isDebugEnabled()) {  
  47.          logger.debug("Found 'Content-Type:" + contentType + "' in response");  
  48.       }  
  49.       selectedMediaType = contentType;  
  50.    }  
  51.    else {  
  52.       HttpServletRequest request = inputMessage.getServletRequest();  
  53.       List<MediaType> acceptableTypes;  
  54.       try {  
  55.          acceptableTypes = getAcceptableMediaTypes(request);  
  56.       }  
  57.       catch (HttpMediaTypeNotAcceptableException ex) {  
  58.          int series = outputMessage.getServletResponse().getStatus() / 100;  
  59.          if (body == null || series == 4 || series == 5) {  
  60.             if (logger.isDebugEnabled()) {  
  61.                logger.debug("Ignoring error response content (if any). " + ex);  
  62.             }  
  63.             return;  
  64.          }  
  65.          throw ex;  
  66.       }  
  67.       List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);  
  68.   
  69.       if (body != null && producibleTypes.isEmpty()) {  
  70.          throw new HttpMessageNotWritableException(  
  71.                "No converter found for return value of type: " + valueType);  
  72.       }  
  73.       List<MediaType> mediaTypesToUse = new ArrayList<>();  
  74.       for (MediaType requestedType : acceptableTypes) {  
  75.          for (MediaType producibleType : producibleTypes) {  
  76.             if (requestedType.isCompatibleWith(producibleType)) {  
  77.                mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));  
  78.             }  
  79.          }  
  80.       }  
  81.       if (mediaTypesToUse.isEmpty()) {  
  82.          if (logger.isDebugEnabled()) {  
  83.             logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);  
  84.          }  
  85.          if (body != null) {  
  86.             throw new HttpMediaTypeNotAcceptableException(producibleTypes);  
  87.          }  
  88.          return;  
  89.       }  
  90.   
  91.       MediaType.sortBySpecificityAndQuality(mediaTypesToUse);  
  92.   
  93.       for (MediaType mediaType : mediaTypesToUse) {  
  94.          if (mediaType.isConcrete()) {  
  95.             selectedMediaType = mediaType;  
  96.             break;  
  97.          }  
  98.          else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {  
  99.             selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;  
  100.             break;  
  101.          }  
  102.       }  
  103.   
  104.       if (logger.isDebugEnabled()) {  
  105.          logger.debug("Using '" + selectedMediaType + "', given " +  
  106.                acceptableTypes + " and supported " + producibleTypes);  
  107.       }  
  108.    }  
  109.    // 根据响应Content-Type格式化返回值,并写到输出流
  110.    if (selectedMediaType != null) {  
  111.       selectedMediaType = selectedMediaType.removeQualityValue();  
  112.       for (HttpMessageConverter<?> converter : this.messageConverters) {  
  113.          GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?  
  114.                (GenericHttpMessageConverter<?>) converter : null);  
  115.          // 根据响应Content-Type获取对应的messageConverter
  116.          if (genericConverter != null ?  
  117.                ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :  
  118.                converter.canWrite(valueType, selectedMediaType)) {  
  119.             // ResponseBodyAdvice的beforeBodyWrite()处理
  120.             body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,  
  121.                   (Class<? extends HttpMessageConverter<?>>) converter.getClass(),  
  122.                   inputMessage, outputMessage);  
  123.             if (body != null) {  
  124.                Object theBody = body;  
  125.                LogFormatUtils.traceDebug(logger, traceOn ->  
  126.                      "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");  
  127.                addContentDispositionHeader(inputMessage, outputMessage);  
  128.                // 通过messageConverter格式化返回值,并写到输出流
  129.                if (genericConverter != null) {  
  130.                   genericConverter.write(body, targetType, selectedMediaType, outputMessage);  
  131.                }  
  132.                else {  
  133.                   ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);  
  134.                }  
  135.             }  
  136.             else {  
  137.                if (logger.isDebugEnabled()) {  
  138.                   logger.debug("Nothing to write: null body");  
  139.                }  
  140.             }  
  141.             return;  
  142.          }  
  143.       }  
  144.    }  
  145. }
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表