网易首页 > 网易号 > 正文 申请入驻

【原创】006| 搭上SpringBoot参数解析返回值处理源码分析专车

0
分享至

  【原创】

  专车介绍

  该趟是开往SpringBoot参数解析和返回值处理源码分析的专车

  专车问题

  第一个问题:SpringBoot是如何解析web请求的参数?

  第二个问题:SpringBoot是如何处理web请求的返回值?

  专车示例

  第一步:定义接口

  @RequestMapping("/persons")
public interface PersonApi {

  /**
* list
*
* @return
*/
@GetMapping("/")
List list();

  /**
* get
*
* @param id
* @return
*/
@GetMapping("/{id}")
Person get(@PathVariable("id") Integer id);

  /**
* add
*
* @param person
* @return
*/
@PostMapping("/")
List add(@Valid @RequestBody Person person);

  /**
* update
*
* @param person
* @return
*/
@PutMapping("/")
List update(@RequestBody Person person);
}

  第二步:定义接口实现

  @RestController
public class PersonController implements PersonApi {

  private static List personList = new ArrayList<>();

  static {
personList.add(new Person(10001, "test1"));
personList.add(new Person(10002, "test2"));
personList.add(new Person(10003, "test3"));
personList.add(new Person(10004, "test4"));
personList.add(new Person(10005, "test5"));
}

  @Override
public List list() {
return personList;
}

  @Override
public Person get(Integer id) {
Person defaultPerson = new Person(88888, "default");
return personList.stream().filter(person -> Objects.equals(person.getId(), id)).findFirst().orElse(defaultPerson);
}

  @Override
public List add(Person person) {
personList.add(person);
return personList;
}

  @Override
public List update(Person person) {
personList.removeIf(p -> Objects.equals(p.getId(), person.getId()));
personList.add(person);
return personList;
}
}

源码拿新增方法来举例,通过该示例来讲解SpringBoot是如何解析请求参数并注入到Person对象中的以及是如何处理值List
专车分析

  在中提到两个重要的对象,一个是RequestMappingHandlerMapping,用来处理请求映射;另一个是RequestMappingHandlerAdapter,用来处理请求,也是本文重点分析的对象

  首先来看看RequestMappingHandlerAdapter的创建实现

  创建RequestMappingHandlerAdapter:WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter

  @Bean
@Override
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter();
adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
|| this.mvcProperties.isIgnoreDefaultModelOnRedirect());
return adapter;
}

  调用父类创建RequestMappingHandlerAdapter:WebMvcConfigurationSupport#requestMappingHandlerAdapter

  @Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// 创建RequestMappingHandlerAdapter
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
// 设置消息转换器
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
// 设置自定义参数解析器
adapter.setCustomArgumentResolvers(getArgumentResolvers());
// 设置自定义返回值处理器
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

  // 如果存在jackson
if (jackson2Present) {
// 设置requestBody通知
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
// 设置responseBody通知
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
// ...省略部分代码
return adapter;
}

如上有给RequestMappingHandlerAdapter对象设置消息转换器,那么这些消息转换器是创建的?

  获取消息转换器:WebMvcConfigurationSupport#getMessageConverters

  protected final List> getMessageConverters() {
if (this.messageConverters == null) {
this.messageConverters = new ArrayList<>();
configureMessageConverters(this.messageConverters);
if (this.messageConverters.isEmpty()) {
// 添加默认消息转换器
addDefaultHttpMessageConverters(this.messageConverters);
}
extendMessageConverters(this.messageConverters);
}
return this.messageConverters;
}

  添加默认消息转换器:WebMvcConfigurationSupport#addDefaultHttpMessageConverters

  protected final void addDefaultHttpMessageConverters(List> messageConverters) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // see SPR-7316

  messageConverters.add(new ByteArrayHttpMessageConverter());
messageConverters.add(stringHttpMessageConverter);
messageConverters.add(new ResourceHttpMessageConverter());
messageConverters.add(new ResourceRegionHttpMessageConverter());
try {
messageConverters.add(new SourceHttpMessageConverter<>());
}
catch (Throwable ex) {
// Ignore when no TransformerFactory implementation is available...
}
messageConverters.add(new AllEncompassingFormHttpMessageConverter());

  if (romePresent) {
messageConverters.add(new AtomFeedHttpMessageConverter());
messageConverters.add(new RssChannelHttpMessageConverter());
}

  if (jackson2XmlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}

  if (jackson2Present) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
}
else if (jsonbPresent) {
messageConverters.add(new JsonbHttpMessageConverter());
}

  if (jackson2SmilePresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}

可以看到此处添加了很多的消息转换器,最终这些消息转换器赋值给了RequestMappingHandlerAdapter对象的messageConverters属性
由于RequestMappingHandlerAdapter实现了InitializingBean接口,那么在该bean创建完成后会调用afterPropertiesSet方法进行一些初始化操作

  初始化操作:RequestMappingHandlerAdapter#afterPropertiesSet

  public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
initControllerAdviceCache();

  if (this.argumentResolvers == null) {
// 获取默认的参数解析器列表
List resolvers = getDefaultArgumentResolvers();
// 创建方法参数解析器对象
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) {
// 获取默认的参数绑定解析器列表
List resolvers = getDefaultInitBinderArgumentResolvers();
// 创建参数绑定解析器对象
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) {
// 获取默认的返回值处理器列表
List handlers = getDefaultReturnValueHandlers();
// 创建返回值处理器对象
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}

如上看到参数解析器、返回值处理器两部分内容,到这就有点味道了,起码看到了点苗头,别急,我们静下心来慢慢分析

  获取默认的参数解析器列表:RequestMappingHandlerAdapter#getDefaultArgumentResolvers

  private List getDefaultArgumentResolvers() {
List 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());

  // Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}

  // Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));

  return resolvers;
}

如上可以看到创建了注解参数解析器、基础类型参数解析器,并添加了自定义解析器

  获取返回值处理器:RequestMappingHandlerAdapter#getDefaultReturnValueHandlers

  private List getDefaultReturnValueHandlers() {
List handlers = new ArrayList<>();

  // Single-purpose return value types
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));

  // Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false));
// 注意此处将消息转换器赋值给了该返回值处理器对象
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
this.contentNegotiationManager, this.requestResponseBodyAdvice));

  // Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler());
handlers.add(new MapMethodProcessor());

  // Custom return value types
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;
}

同样的创建一系列的返回值处理器
到此,参数解析器和返回值处理器都已经创建好,并赋值给了RequestMappingHandlerAdapter对象,有了参数解析器和返回值处理器,那么就可以解析请求参数、处理请求返回值了。接下来就看看请求处理过程中是如何使用参数解析器和返回值处理器的。
请求处理

  调用处理方法:RequestMappingHandlerAdapter#invokeHandlerMethod

  protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

  ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

  // 使用handlerMethod对象来构建ServletInvocableHandlerMethod对象,也就是完成属性的赋值,此对象很重要,后续的所有操作都和该对象有关
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
// 将之前的参数解析器对象赋值给ServletInvocableHandlerMethod对象
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
// 将之前的返回值处理器对象赋值给ServletInvocableHandlerMethod对象
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
// ...省略部分代码
// 执行请求并处理返回值
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

  return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}

  执行请求并处理返回值:ServletInvocableHandlerMethod#invokeAndHandle

  public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 执行请求
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);

  // ...省略部分代码

  mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 处理返回结果
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
执行请求

  执行请求:InvocableHandlerMethod#invokeForRequest

  public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 解析方法参数列表信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 执行目标方法
return doInvoke(args);
}

  解析方法参数:InvocableHandlerMethod#getMethodArgumentValues

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

  // 获取方法参数对象列表信息
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}

  Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 遍历所有的参数解析器,如果所有的参数解析器都无法解析该参数,直接报错
// 此处符合条件的参数解析器为RequestResponseBodyMethodProcessor
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 使用RequestResponseBodyMethodProcessor参数解析器来解析当前参数信息
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
// ... 省略部分代码
}
return args;
}

为什么符合条件的参数解析器为RequestResponseBodyMethodProcessor
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
可以看到该参数解析器用来解析用@RequestBody注解修饰的参数信息

  使用参数解析器解析参数: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());
// ...省略部分代码
return adaptArgumentIfNecessary(arg, parameter);
}

  使用转换器读取参数信息:

  AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(org.springframework.http.HttpInputMessage, org.springframework.core.MethodParameter, java.lang.reflect.Type)

  protected Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

  MediaType contentType;
boolean noContentType = false;
try {
// 从请求头中读取请求的类型,比如application/json
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
// 如果请求类型为空,默认请求类型为application/octet-stream,请求的是一个二进制流
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}

  // 参数类型
Class contextClass = parameter.getContainingClass();
Class targetClass = (targetType instanceof Class ? (Class) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class) resolvableType.resolve();
}

  HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;

  EmptyBodyCheckingHttpInputMessage message;
try {
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);

  // 遍历所有的消息转换器,找到最终可以读取数据的消息转换器
for (HttpMessageConverter converter : this.messageConverters) {
Class> converterType = (Class>) converter.getClass();
GenericHttpMessageConverter genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null);
// 由于我们的请求类型为application/json,所以此处可以读取数据的消息转换器为MappingJackson2HttpMessageConverter
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {

  if (message.hasBody()) {
// ...省略部分代码

  // 使用MappingJackson2HttpMessageConverter读取数据并返回
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter) converter).read(targetClass, msgToUse));
// ...省略部分代码
}
else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
}
// ...省略部分代码
return body;
}

  消息转换器读取数据:AbstractJackson2HttpMessageConverter#readJavaType

  private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
try {
// ...省略部分代码

  // 使用jackson从请求体中读取数据
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
}
}

读取请求参数的部分到此就结束了,返回到执行请求的代码

  执行请求:InvocableHandlerMethod#invokeForRequest

  public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 解析并获取到方法参数信息
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 利用反射来调用目标方法,获取方法的返回值
return doInvoke(args);
}

拿到返回数据之后,接下来就是如何处理返回值
处理返回值

  请求并处理:ServletInvocableHandlerMethod#invokeAndHandle

  public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// ...省略部分代码
try {
// 使用返回值处理器来处理返回值
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}

  使用返回值处理器处理返回值:HandlerMethodReturnValueHandlerComposite#handleReturnValue

  @Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 选择返回值处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
// 如果返回值处理器为空,直接抛出异常
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
// 使用返回值处理器处理返回值
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

  选择返回值处理器:HandlerMethodReturnValueHandlerComposite#selectHandler

  @Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
// 是否为异步返回值
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
// 遍历所有的返回值处理器
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
// 如果当前返回值处理器支持当前返回值类型,直接返回。此处符合要求的是RequestResponseBodyMethodProcessor处理器
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}

为什么符合要求的是RequestResponseBodyMethodProcessor返回值处理器?
@Override
public boolean supportsReturnType(MethodParameter returnType) {
// 如果所在的类含有@ResponseBody注解或者方法含有@ResponseBody注解,返回true
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}

  使用返回值处理返回值:RequestResponseBodyMethodProcessor#handleReturnValue

  @Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

  mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

  // Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

  消息转换器转换返回数据:AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

  protected void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

  Object body;
Class valueType;
Type targetType;

  // ...省略部分代码

  if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue();
// 遍历消息转换器,找到合适的消息转换器将数据写到客户端
for (HttpMessageConverter converter : this.messageConverters) {
GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
(GenericHttpMessageConverter) converter : null);
if (genericConverter != null ?
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
converter.canWrite(valueType, selectedMediaType)) {
// ...省略部分代码
if (body != null) {
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn ->
"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
addContentDispositionHeader(inputMessage, outputMessage);
if (genericConverter != null) {
// 将数据写回客户端
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
} else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
// ...省略部分代码
return;
}
}
}

  if (body != null) {
throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
}
}

返回值处理部分到此也结束了
专车回顾

  第一个问题:SpringBoot是如何解析请求参数的?首先会创建一系列的消息转换器,然后在创建一系列的处理器,处理器中包含了消息转换器,在请求的时候找到对应的处理器,然后根据请求类型找到对应的转换器,进行参数解析

  第二个问题:SpringBoot是如何处理请求返回值?同样是消息转换器,返回值处理器,根据返回的标识选择对应的处理器,找到相应的消息转换器,然后使用消息转换器往客户端写数据。

  专车总结

  创建RequestMappingHandlerAdapter对象

  设置消息转换器

  在初始化afterPropertiesSet方法中初始化参数解析器、返回值处理器

  创建ServletInvocableHandlerMethod对象,设置参数解析器、返回值处理器

  使用RequestResponseBodyMethodProcessor参数解析器的MappingJackson2HttpMessageConverter消息转换器读取参数

  使用RequestResponseBodyMethodProcessor返回值处理器的MappingJackson2HttpMessageConverter消息转换器处理返回值

  ———— e n d ————

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
这不能再被逆了吧?热火三节领先公牛22分!

这不能再被逆了吧?热火三节领先公牛22分!

直播吧
2024-04-20 09:03:11
最高罚200万,东莞发布规范水电费收费行为告诫书

最高罚200万,东莞发布规范水电费收费行为告诫书

南方都市报
2024-04-19 21:20:19
5任市长落马后,广东这座城市又有市领导被双开

5任市长落马后,广东这座城市又有市领导被双开

中国青年报
2024-04-18 20:31:11
又见面了小兄弟!马塞洛儿子恩佐晒与C罗儿子合照

又见面了小兄弟!马塞洛儿子恩佐晒与C罗儿子合照

娱乐圈酸柠檬
2024-04-19 21:12:44
北京二手房挂牌量上涨38%

北京二手房挂牌量上涨38%

小豆豆赛事
2024-04-20 03:08:38
“乱港头目”陈方安生:曾是香港二号人物,搞乱香港后成过街老鼠

“乱港头目”陈方安生:曾是香港二号人物,搞乱香港后成过街老鼠

清欢渡语
2024-04-16 21:45:50
大胜张禹珍,韩国队盘外招,王楚钦11:2回应,谁注意韩国教练表情

大胜张禹珍,韩国队盘外招,王楚钦11:2回应,谁注意韩国教练表情

东球弟
2024-04-19 22:13:04
军中巨虎畏罪自杀,刘源将军:比徐和郭问题严重!

军中巨虎畏罪自杀,刘源将军:比徐和郭问题严重!

我是娱有理
2024-04-16 07:18:56
联合国大会罕见一幕,以色列讲话,多国代表离席,中方留下干大事

联合国大会罕见一幕,以色列讲话,多国代表离席,中方留下干大事

曹兴教授TALK
2024-04-19 22:15:03
海康威视:2024年一季度净利润19.16亿元

海康威视:2024年一季度净利润19.16亿元

南方都市报
2024-04-20 01:20:11
闹大了!人民法治都报道了:老人4月燃气费12000,是往年的三四倍

闹大了!人民法治都报道了:老人4月燃气费12000,是往年的三四倍

杂谈哥闲谈
2024-04-18 23:13:32
14中13怒砍29+8!2米01迷你内线打爆王哲林,上海防不住他难进4强

14中13怒砍29+8!2米01迷你内线打爆王哲林,上海防不住他难进4强

弄月公子
2024-04-19 23:03:04
吴艳妮:文静的我 ,可能一到场地就会把衣服一脱来个跨栏

吴艳妮:文静的我 ,可能一到场地就会把衣服一脱来个跨栏

懂球帝
2024-04-19 11:04:14
老婆让她闺蜜给我做个男科手术,半梦半醒之间,我感觉自己下半身的触感不对劲

老婆让她闺蜜给我做个男科手术,半梦半醒之间,我感觉自己下半身的触感不对劲

户外阿崭
2024-04-18 11:15:48
防水的可伸缩镜头,华为是怎么做到的?遥遥领先设计之拆解分析

防水的可伸缩镜头,华为是怎么做到的?遥遥领先设计之拆解分析

真义科技
2024-04-19 11:07:30
抛弃激光雷达?华为重大宣布!完全超越特斯拉!

抛弃激光雷达?华为重大宣布!完全超越特斯拉!

吃鱼思故渊
2024-04-17 21:53:38
清华教授:没有特斯拉开放专利,就没有中国新能源的今天

清华教授:没有特斯拉开放专利,就没有中国新能源的今天

玩车情报
2024-04-19 22:18:12
“老虎”被诉!国开行原副行长王用生被控“非法收受财物,数额特别巨大”

“老虎”被诉!国开行原副行长王用生被控“非法收受财物,数额特别巨大”

政知新媒体
2024-04-19 15:30:31
纳斯里称大马丁的态度让自己不爽,球迷评论:看到你不爽让我巨爽

纳斯里称大马丁的态度让自己不爽,球迷评论:看到你不爽让我巨爽

直播吧
2024-04-20 06:55:18
变天了,中美谈崩,德国总理访华,美媒:美国最大的敌人不是中俄

变天了,中美谈崩,德国总理访华,美媒:美国最大的敌人不是中俄

关权教授聊经济
2024-04-19 19:25:03
2024-04-20 09:12:49
Meta
Meta
关注java进阶架构师送架构
1041文章数 9851关注度
往期回顾 全部

科技要闻

华为今年最关键的事曝光!Pura 70有新消息

头条要闻

媒体:以色列所谓“导弹袭击”伊朗可能只是虚惊一场

头条要闻

媒体:以色列所谓“导弹袭击”伊朗可能只是虚惊一场

体育要闻

米切尔这次对线不会输了吧

娱乐要闻

北影节开幕之夜,内娱女星千娇百媚

财经要闻

新华资管香港的秘密:猛投地产或致巨亏

汽车要闻

风神L7预售 东风汽车北京车展阵容公布

态度原创

旅游
时尚
艺术
亲子
手机

旅游要闻

西宁“下南关”:高原老街的烟火气

放弃牛仔裤吧,入夏是穿“裙子”的季节!遮肉显瘦谁穿谁优雅

艺术要闻

最全展览单元剧透!北京最受瞩目艺术现场100青年艺术季终极解读

亲子要闻

女儿每次吃肉都要吃一大碗,妈妈本想劝她不料反被她套路,女儿:想揍我就直说!

手机要闻

华为鸿蒙OS 4.2:主要亮点汇总,花粉反馈也已出炉!

无障碍浏览 进入关怀版