【Spring Boot】响应JSON实现原理
1、ReturnValueHandlers—返回值处理器
之前我们分析了参数解析器argumentResolvers的相关源码,了解了请求中的参数是如何找到合适的参数解析器,并与方法的入参进行绑定的,那么问题来了,响应值的返回值处理器是如何找到的呢?
要分析源码,我们还是得进入DispatcherServlet这个类下的doDiapatch()方法
与之前分析参数解析器一样的流程,我们跟到了RequestMappingHandlerAdapter这个类下的invokeHandlerMethod()方法
通过断点可以看到我们默认支持15种返回值解析器
那么他是怎么从这么多返回值解析器中选出自己支持的那一个呢?
我们可以发现,这些返回值解析器都是实现了HandlerMethodReturnValueHandler接口
package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.context.request.NativeWebRequest;
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
此接口下只有2个方法,一个是判断是否支持此类型返回值,另一个是处理返回值的方法
是不是和之前的参数解析器的接口类有异曲同工之妙?
没错,我们正是使用这两个方法来寻找适合自己的返回值解析器以及处理我们的返回值
跟着断点一直向下,我们跟到了HandlerMethodReturnValueHandlerComposite类下的handleReturnValue()方法,在这里,我们就找到了对应的解析器并执行了相关方法
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 获取自己适合的返回值解析器
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
// 调用该返回值解析器中的处理返回值的方法
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
// 判断是否是异步的返回值
boolean isAsyncValue = this.isAsyncReturnValue(value, returnType);
Iterator var4 = this.returnValueHandlers.iterator();
HandlerMethodReturnValueHandler handler;
// 使用do-while进行遍历,找出支持当前返回值类型的解析器
do {
do {
if (!var4.hasNext()) {
return null;
}
handler = (HandlerMethodReturnValueHandler)var4.next();
} while(isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler));
} while(!handler.supportsReturnType(returnType));
return handler;
}
最终,我们确定使用解析器RequestResponseBodyMethodProcessor可以处理标注了@ResponseBody的返回值
2、HttpMessageConvert—消息转换器
除了寻找合适的返回值解析器之外,我们还有一个问题要思考
为什么我们在控制器类的方法上加一个@ResponseBody注解就能将响应信息转换成json格式呢?
这个转换是怎样实现的呢?
我们接着上面的代码继续往下debug
之前我们已经定位到了使用RequestResponseBodyMethodProcessor来处理@ResponseBody的返回值,所以我们继续深入到这个类下的handleReturnValue()
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
// 创建输入和输出信息
ServletServerHttpRequest inputMessage = this.createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = this.createOutputMessage(webRequest);
// 使用消息转换器进行写出操作
this.writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
然后我们来分析解析器父类AbstractMessageConverterMethodProcessor下的writeWithMessageConverters()方法
首先我们了解一个概念:什么是内容协商?
浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型,这里的q代表优先级
然后服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据
所以在writeWithMessageConverters()方法中我们获取到浏览器能接受什么内容
以及服务器能产生什么内容
然后我们经过协商,决定返回application/json格式的数据
重点来了:这里有一系列的消息转换器,我们到底使用哪个呢?
随便点进一个消息转换器,我们发现他都是实现了HttpMessageConverter这个接口
这里面有2个方法,canRead()和canWrite()来帮助我们判断能否支持源类型和目标类型的消息读写
最终我们确定了,使用MappingJackson2HttpMessageConverter这个消息转换器来进行json转换
package org.springframework.http.converter;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
public interface HttpMessageConverter<T> {
// 读取,例如将json转为Person对象
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
// 写出,例如将Person转为json对象
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
default List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
return !this.canRead(clazz, (MediaType)null) && !this.canWrite(clazz, (MediaType)null) ? Collections.emptyList() : this.getSupportedMediaTypes();
}
T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;
}
然后我们在此处调用MappingJackson2HttpMessageConverter父类AbstractGenericHttpMessageConverter中的write()方法
走到AbstractJackson2HttpMessageConverter类下的writeInternal()方法
可以看出,它利用了底层的Jackson的objectMapper进行转换
这样,我们就完成了Person数据到json格式的转换
如有错误,欢迎指正!!!