SpringMVC中参数是如何绑定and返回结果是如何解析的?

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: SpringMVC中参数是如何绑定and返回结果是如何解析的?

关联博文:

SpringMVC常见组件之HandlerAdapter分析

SpringMVC常见组件之HandlerMethodArgumentResolver解析

SpringMVC常见组件之HandlerMethodReturnValueHandler解析


这里框架背景为SpringBoot 2.2.4.RELEASE,不同版本下某些流程可能不同。


如果你曾经跟踪过请求流程或者在某个博客看到过请求流程源码,比如SpringBoot中添加@ResponseBody注解会发生什么?,你应该知道参数解析是由各种各样的HandlerMethodArgumentResolver(参数解析器)处理的。不同类型的参数会有对应的参数解析器处理。

【RequestMappingHandlerAdapter.afterPropertiesSet

① HandlerMethodArgumentResolver源码

public interface HandlerMethodArgumentResolver {
//判断当前解析器是否能够解析该类型参数
  boolean supportsParameter(MethodParameter parameter);
//获取当前参数对象的值,通过mavContainer可以获取model,通过binderFactory可以获取WebDataBinder实例对象
//WebDataBinder用来进行数据绑定、参数类型转换
  @Nullable
  Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}


在springboot启动时其中一步finishBeanFactoryInitialization会对一些bean进行预初始化,RequestMappingHandlerAdapter就是在这里被实例化的。


② 在afterPropertiesSet方法中,其会获取一些全局配置、参数解析器等

源码如下所示:

@Override
public void afterPropertiesSet() {
  // 获取标注了@ControllerAdvice注解的bean
  initControllerAdviceCache();
//获取默认的参数解析器
  if (this.argumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
    this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
  }
//获取@InitBinder注解使用的参数解析器
  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);
  }
}


这里有个细节需要注意,获取的默认参数解析器、@InitBinder注解使用的参数解析器或者返回结果处理器均是有序的列表。有序的意思是当遍历解析器找到当前参数合适的解析器时,如果前面的解析器能够处理,那么就会直接返回(即使后面有参数解析器同样能够处理)


如下所示,解析参数时首先遍历获取合适的参数解析器(HandlerMethodArgumentResolverComposite.getArgumentResolver):

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


RequestMappingHandlerAdapter实例化时注册了26个默认的参数解析器:

20200710090616583.png

③ initControllerAdviceCache

源码如下:

privprivate void initControllerAdviceCache() {
  if (getApplicationContext() == null) {
    return;
  }
//获取标注了注解@ControllerAdvice的类,封装为一个个ControllerAdviceBean并使用OrderComparator排序
  List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
  List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
//遍历adviceBeans 
  for (ControllerAdviceBean adviceBean : adviceBeans) {
    Class<?> beanType = adviceBean.getBeanType();
    if (beanType == null) {
      throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
    }
//获取adviceBean 中@ModelAttribute注解且没有@RequestMapping注解的方法      
    Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
    if (!attrMethods.isEmpty()) {
      this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
    }
//获取adviceBean 中@InitBinder注解的方法      
    Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
    if (!binderMethods.isEmpty()) {
      this.initBinderAdviceCache.put(adviceBean, binderMethods);
    }
//获取requestResponseBodyAdviceBeans类型的bean:RequestBodyAdvice或者ResponseBodyAdvice
    if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
      requestResponseBodyAdviceBeans.add(adviceBean);
    }
  }
  if (!requestResponseBodyAdviceBeans.isEmpty()) {
    this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
  }
//几种类型数量统计
  if (logger.isDebugEnabled()) {
    int modelSize = this.modelAttributeAdviceCache.size();
    int binderSize = this.initBinderAdviceCache.size();
    int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
    int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
    if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
      logger.debug("ControllerAdvice beans: none");
    }
    else {
      logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
          " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
    }
  }
}



④ 获取默认的参数解析器getDefaultArgumentResolvers

方法源码如下:

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
  List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
  // 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 (getCustomArgumentResolvers() != null) {
    resolvers.addAll(getCustomArgumentResolvers());
  }
  // Catch-all  这个注释很有意思Catch-all表示当你没有显示表明什么注解也不是httpsession map等基础参数类型时
  //就会尝试使用下面这两种参数解析器
  //1.RequestParamMethodArgumentResolver 针对简单类型
  //2.针对复杂类型,如User
  resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
  resolvers.add(new ServletModelAttributeMethodProcessor(true));
  return resolvers;
}


⑤ 获取InitBinder注解方法的参数解析器getDefaultInitBinderArgumentResolvers

方法源码如下(参考④ 这里不再解释):

private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
  List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
  // 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 ExpressionValueMethodArgumentResolver(getBeanFactory()));
  resolvers.add(new SessionAttributeMethodArgumentResolver());
  resolvers.add(new RequestAttributeMethodArgumentResolver());
  // Type-based argument resolution
  resolvers.add(new ServletRequestMethodArgumentResolver());
  resolvers.add(new ServletResponseMethodArgumentResolver());
  // Custom arguments
  if (getCustomArgumentResolvers() != null) {
    resolvers.addAll(getCustomArgumentResolvers());
  }
  // Catch-all
  resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
  return resolvers;
}


⑥ 获取方法返回结果处理器getDefaultReturnValueHandlers

方法源码如下:

private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
  List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
  // 处理单一返回类型
  handlers.add(new ModelAndViewMethodReturnValueHandler());
  handlers.add(new ModelMethodProcessor());
  handlers.add(new ViewMethodReturnValueHandler());
  handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters(),
      this.reactiveAdapterRegistry, this.taskExecutor, this.contentNegotiationManager));
  handlers.add(new StreamingResponseBodyReturnValueHandler());
  handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
      this.contentNegotiationManager, this.requestResponseBodyAdvice));
  handlers.add(new HttpHeadersReturnValueHandler());
  handlers.add(new CallableMethodReturnValueHandler());
  handlers.add(new DeferredResultMethodReturnValueHandler());
  handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
  // 处理方法上面有@ModelAttribute 或者@ResponseBody注解
  handlers.add(new ModelAttributeMethodProcessor(false));
  handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
      this.contentNegotiationManager, this.requestResponseBodyAdvice));
  // 处理多个返回类型
  handlers.add(new ViewNameMethodReturnValueHandler());
  handlers.add(new MapMethodProcessor());
  // 自定义返回结果处理器
  if (getCustomReturnValueHandlers() != null) {
    handlers.addAll(getCustomReturnValueHandlers());
  }
  // Catch-all---最后的希望
  if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
    handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
  }
  else {
    handlers.add(new ModelAttributeMethodProcessor(true));
  }
  return handlers;
}


2】不同参数解析器处理对应的参数类型

① 简单类型默认参数解析器RequestParamMethodArgumentResolver

RequestParamMethodArgumentResolver主要用来处理标注了@RequestParam注解的方法参数,有时会与其他解析器配合使用。如与MultipartResolver配合对MultipartFile类型参数进行处理。


当方法参数没有使用注解标明的时候,通常RequestParamMethodArgumentResolver会默认用来处理简单类型的参数如int long String等。


其类继承示意图如下(绿色虚线表示其实现接口):


② RequestParamMapMethodArgumentResolver解析Map类型的参数

RequestParamMapMethodArgumentResolver用来处理参数类型为Map(或MultiValueMap)、参数使用了@RequestParam注解但是并没有指定@RequestParam注解的name属性值。


解析后的map会包含请求中所有与的参数键值对,或者是值类型为MultipartFile的参数键值对

③ URI参数解析PathVariableMethodArgumentResolver


PathVariableMethodArgumentResolver将会从URI上面解析参数赋值给方法参数,也就是方法参数标注了@PathVariable注解。


如果参数类型为Map时,则必须指定@PathVariable注解的name属性或者value属性(但是前提示已经注册了一个合适的类型转换器或者PropertyEditor,否则将会抛出异常!)。


如果@PathVariable注解指定了name属性或者value属性,但是与URI占位符里面变量不一致,将会抛出类似于org.springframework.web.bind.MissingPathVariableException: Missing URI template variable 'param' for method parameter of type Map异常。

④ URI参数解析之PathVariableMapMethodArgumentResolver

PathVariableMapMethodArgumentResolver将会解析标注了@PathVariable注解、参数类型为Map且没有指定@PathVariable注解的name属性或value属性。以占位符里面的id为key,参数值为value赋值给param。

⑤ MatrixVariableMethodArgumentResolver

解析@MatrixVariable注解标注的参数,如果参数类型是Map,通常会被MatrixVariableMapMethodArgumentResolver解析器处理除非该注解指定了name属性。

20200709195354967.png


⑥ MatrixVariableMapMethodArgumentResolver

解析使用了@MatrixVariable标注的Map类型的参数,且@MatrixVariable注解没有指定name属性。


⑦ 复杂类型对象解析器ServletModelAttributeMethodProcessor与ModelAttributeMethodProcessor


ServletModelAttributeMethodProcessor是ModelAttributeMethodProcessor的子类,可以解析复杂类型对象,如User。当构造方法参数annotationNotRequired为true时,那么无论方法参数是否使用了@ModelAttribute注解,都会被这两个解析器处理。该参数解析器同样适用于@ModelAttribute注解的方法。


20200709201527716.png


数据绑定过程大概如下

  • 确定key

如果使用了@ModelAttribute注解且指定了其name属性,那么参数的key就是name属性值;否则为对象首字母小写,如TbSysAdmin–>tbSysAdmin。



确定value/target对象


尝试从model中获取,如果获取到就返回;

尝试从UriTemplateVariables或request根据key获取value,如果获取到就返回;

使用构造器实例化一个空对象-target


bindRequestParameters(binder, webRequest)


从请求中获取参数键值对对binder中的target进行数据绑定


把得到的参数值扔给方法参数

⑧ RequestResponseBodyMethodProcessor


该注解通常用来处理方法参数上标注了@RequestBody注解或者方法上面标注了@ResponseBody注解。其会使用HttpMessageConverter从request中读取数据赋值给参数或者把方法返回结果写到response中。其同样作为返回结果处理器使用。




⑨ RequestPartMethodArgumentResolver

该解析器用来处理如下类型参数:


  • 标注了@RequestPart注解的参数
  • 与MultipartResolver配合使用解析MultipartFile类型
  • 与Servlet 3.0 multipart requests配合处理javax.servlet.http.Part类型




(10)请求头处理RequestHeaderMethodArgumentResolver

解析标注了@RequestHeader注解的方法参数,除了Map类型。



(11)请求头处理RequestHeaderMapMethodArgumentResolver

解析标注了@RequestHeader注解的Map类型的参数。


(12)Cookie解析器ServletCookieValueMethodArgumentResolver

从HttpServletRequest获取cookie 值。


(13)${...}#{...}表达式解析器ExpressionValueMethodArgumentResolver

解析标注了 @Value注解的方法参数,该注解通常使用${...}或者#{...} 来表示值。


(14)session属性解析器SessionAttributeMethodArgumentResolver

该解析器用来处理标注了@SessionAttribute的方法参数,也就是根据name从session里面获取值。


(15)request属性解析器RequestAttributeMethodArgumentResolver

该解析器用来处理标注了@RequestAttribute的方法参数,也就是根据name从request里面获取值。



下面是Type-based argument resolution的一些参数解析器。


(16)请求相关的参数解析器ServletRequestMethodArgumentResolver

该解析器用来处理如下类型的参数:

  • WebRequest
  • ServletRequest
  • MultipartRequest
  • HttpSession
  • PushBuilder
  • Principal
  • InputStream
  • Reader
  • HttpMethod
  • Locale
  • TimeZone
  • java.time.ZoneId


(17)响应相关的参数解析器ServletResponseMethodArgumentResolver

该参数解析器主要用来处理如下类型参数:

  • ServletResponse
  • OutputStream
  • Writer



(18)HttpEntityMethodProcessor

该解析器用来处理HttpEntity和RequestEntity类型参数,以及HttpEntity和ResponseEntity返回类型。其同样作为返回结果处理器使用。



(19)重定向属性解析RedirectAttributesMethodArgumentResolver

该解析器用来处理方法参数为RedirectAttributes类型的,其必须在解析Model类型参数的ModelMethodProcessor和解析Map类型参数的MapMethodProcessor之前加载。因为后者均可以尝试解析RedirectAttributes类型的参数。


20200710135802436.png


那么什么是RedirectAttributes?如何使用RedirectAttributes?


RedirectAttributes是继承自Model的一个特殊接口,可以在请求重定向时传递参数使用。唯一实现类为RedirectAttributesModelMap其有属性ModelMap flashAttributes用来存放重定向过程中的数据给重定向后的方法使用:




20200710140006267.png



在Controller中使用RedirectAttributes 实例如下:

@RequestMapping(value = "/accounts", method = RequestMethod.POST)
public String handle(Account account, BindingResult result, RedirectAttributes redirectAttrs) {
   if (result.hasErrors()) {
     return "accounts/new";
   }
   // Save account ...
   redirectAttrs.addAttribute("id", account.getId()).addFlashAttribute("message", "Account created!");
   return "redirect:/accounts/{id}";
}



(20)Model类型参数解析器ModelMethodProcessor

该解析器用来处理方法参数类型为Model或者返回结果为Model,其应该注册于那些支持@ModelAttribute、@ResponseBody的处理器之前。其同样作为返回结果处理器使用。



那么什么是Model?

其实java5定义的一个容器接口,用来保存属性键值。通常获取model中的数据是将其作为一个Map进行操作。实现类如:



其中最常见的BindingAwareModelMap类继承图如下:




其中最常见的BindingAwareModelMap类继承图如下:




(22)Errors类型参数解析器ErrorsMethodArgumentResolver

解析Errors类型的方法参数。Errors通常与model attribute一起出现,作为接收错误对象的参数使用。



(23)SessionStatus类型参数解析器SessionStatusMethodArgumentResolver

解析SessionStatus类型的参数,从ModelAndViewContainer获取SessionStatus:

@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
    NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
  Assert.state(mavContainer != null, "ModelAndViewContainer is required for session status exposure");
  return mavContainer.getSessionStatus();
}



(24)UriComponentsBuilderMethodArgumentResolver

解析UriComponentsBuilder类型的参数。


(25)默认的、简单类型参数解析器RequestParamMethodArgumentResolver

这里useDefaultResolution 为true:

new RequestParamMethodArgumentResolver(getBeanFactory(), true)
public RequestParamMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory,
      boolean useDefaultResolution) {
    super(beanFactory);
    this.useDefaultResolution = useDefaultResolution;
  }


(26)默认的、复杂类型参数解析器ServletModelAttributeMethodProcessor

这里annotationNotRequired为true,其同样作为返回结果处理器使用。

new ServletModelAttributeMethodProcessor(true)
public ServletModelAttributeMethodProcessor(boolean annotationNotRequired) {
  super(annotationNotRequired);
}



20200710144241480.png

【3】返回结果处理器与返回结果类型

① 视图处理器ModelAndViewMethodReturnValueHandler

处理返回结果类型为ModelAndView的方法,将会把view和model赋值给mavContainer。如果返回结果为null,则ModelAndViewContainer.setRequestHandled(true)来标明请求已经被直接处理完毕。

20200710152440957.png


② Model返回结果处理器ModelMethodProcessor

处理方法参数为Model类型和返回结果类型为Model的方法。其不仅仅是返回结果处理器,也是方法参数解析器。


③ View返回结果处理器ViewMethodReturnValueHandler

该解析器用来处理返回结果为View类型的方法。


④ ResponseBodyEmitter返回结果处理ResponseBodyEmitterReturnValueHandler

该解析器用来处理返回结果为ResponseBodyEmitter或其子类如用ResponseEntity包装的。


⑤ StreamingResponseBodyReturnValueHandler

该解析器用来处理返回结果为StreamingResponseBody和ResponseEntity<StreamingResponseBody>的方法。


⑥ HttpEntityMethodProcessor

作为参数解析器用来解析HttpEntity和RequestEntity。作为返回结果处理器用来处理HttpEntity和ResponseEntity的类型。



⑦ HttpHeadersReturnValueHandler

处理返回结果类型为HttpHeaders的方法。

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
    ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//设置请求处理标志位true
  mavContainer.setRequestHandled(true);
  Assert.state(returnValue instanceof HttpHeaders, "HttpHeaders expected");
  HttpHeaders headers = (HttpHeaders) returnValue;
//如果headers 不为空,就放入outputMessage.getHeaders()中
  if (!headers.isEmpty()) {
    HttpServletResponse servletResponse = webRequest.getNativeResponse(HttpServletResponse.class);
    Assert.state(servletResponse != null, "No HttpServletResponse");
    ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(servletResponse);
    outputMessage.getHeaders().putAll(headers);
    outputMessage.getBody();  // flush headers
  }
}


⑧ CallableMethodReturnValueHandler

处理返回结果类型为Callable的方法,通常用于异常处理。

public class CallableMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
  @Override
  public boolean supportsReturnType(MethodParameter returnType) {
    return Callable.class.isAssignableFrom(returnType.getParameterType());
  }
  @Override
  public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    if (returnValue == null) {
      mavContainer.setRequestHandled(true);
      return;
    }
//如下进行异步回调
    Callable<?> callable = (Callable<?>) returnValue;
    WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
  }
}


DeferredResultMethodReturnValueHandler

处理方法返回结果类型为DeferredResult、ListenableFuture以及CompletionStage的方法。


⑩异步任务处理器AsyncTaskMethodReturnValueHandler

处理方法返回结果为WebAsyncTask的。

(11)@ModelAttribute标注的方法处理器ModelAttributeMethodProcessor

new ModelAttributeMethodProcessor(false)

作为参数解析器用来处理@ModelAttribute标注的方法参数,作为结果处理器用来处理@ModelAttribute标注的方法返回结果。

作为参数解析器用来处理@ModelAttribute标注的方法参数,作为结果处理器用来处理@ModelAttribute标注的方法返回结果。



(12)RequestResponseBodyMethodProcessor

new RequestResponseBodyMethodProcessor(getMessageConverters(),
        this.contentNegotiationManager, this.requestResponseBodyAdvice)



作为参数解析器用来处理@RequestBody注解的参数,作为返回结果处理器用来处理方法标注了@ResponseBody的返回结果。通常会与HttpMessageConverter配合使用,用来从request读取数据或向response写入数据。



(13)视图名字结果处理器ViewNameMethodReturnValueHandler

可以处理如下返回结果类型:

  • void
  • String
  • CharSequence
  • StringBuilder
  • GString


将返回结果作为view name进行处理。



(14)MapMethodProcessor

作为参数解析器用来处理Map类型参数,作为返回结果处理器用来处理Map类型结果。当作为前者时,其会从mavContainer获取model赋值给方法参数;当作为后者时,其会把返回结果放入mavContainer的model中。

20200710160651859.png



(15)最后的希望ModelAndViewResolverMethodReturnValueHandler与ModelAttributeMethodProcessor

如果有ModelAndViewResolver那么会注册ModelAndViewResolverMethodReturnValueHandler否则会注册new ModelAttributeMethodProcessor(true),true的意思是不管是否有@ModelAttribute注解,复杂对象类型的返回结果最后会被该解析器尝试处理(非空的返回结果会被放入mavContainer的model中)。

if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
}
else {
  handlers.add(new ModelAttributeMethodProcessor(true));
}



ModelAttributeMethodProcessor已经很熟悉了,那么ModelAndViewResolverMethodReturnValueHandler是什么?


目录
相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
93 2
|
15天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
21天前
|
JSON 自然语言处理 Java
OpenAI API深度解析:参数、Token、计费与多种调用方式
随着人工智能技术的飞速发展,OpenAI API已成为许多开发者和企业的得力助手。本文将深入探讨OpenAI API的参数、Token、计费方式,以及如何通过Rest API(以Postman为例)、Java API调用、工具调用等方式实现与OpenAI的交互,并特别关注调用具有视觉功能的GPT-4o使用本地图片的功能。此外,本文还将介绍JSON模式、可重现输出的seed机制、使用代码统计Token数量、开发控制台循环聊天,以及基于最大Token数量的消息列表限制和会话长度管理的控制台循环聊天。
158 7
|
3月前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
2月前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
41 2
Spring高手之路25——深入解析事务管理的切面本质
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
80 8
|
2月前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
153 2
|
2月前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
64 2
|
2月前
|
前端开发 Java Maven
深入解析:如何用 Spring Boot 实现分页和排序
深入解析:如何用 Spring Boot 实现分页和排序
66 2
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
51 4

推荐镜像

更多
下一篇
开通oss服务