3.1 @ResponseBody
通常我们可以在 Controller 或方法上标注 @ResponseBody 注解以表示需要将对象转为 JSON 并返回给前端,那么 Spring MVC 是如何自动完成这一过程的呢?
从前面初始化-容器初始化-容器创建-配置解析一节可以看出,Spring MVC 采用 org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser 进行配置的解析,核心的 parse 方法中完成了对 HttpMessageConverter 的初始化。
HttpMessageConverter
Spring 的 HttpMessageConverter 接口负责 HTTP 请求-Java 对象与 Java 对象-响应之间的转换。我们以 Spring 默认使用的 Jackson 转换器为例,类图:

HttpMessageConverter 实现的初始化由 AnnotationDrivenBeanDefinitionParser 的 getMessageConverters 方法完成,HttpMessageConverter 的来源分为自定义和默认。
示例配置:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="test.Converter" />
</mvc:message-converters>
</mvc:annotation-driven>
自定义
Spring 允许我们通过 XML 配置文件的 message-converters 元素来进行自定义。
默认
当 检测到没有配置 message-converters 元素或者 register-defaults="true"时 Spring 便会注册默认转换器 。这其中便包括 MappingJacksonHttpMessageConverter,相关源码:
else if (jacksonPresent) {
messageConverters.add(createConverterDefinition(
org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.class, source));
}
jacksonPresent 声明:
private static final boolean jacksonPresent =
ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()) &&
ClassUtils.isPresent("org.codehaus.jackson.JsonGenerator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
转换
入口位于 ServletInvocableHandlerMethod 的 invokeAndHandle 方法对于响应的处理:
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
returnValueHandlers 其实就是 RequestMappingHandlerAdapter 内部的 returnValueHandlers,后者由 RequestMappingHandlerAdapter 的 afterPropertiesSet 方法初始化,关键在于:
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager));
对象到 JSON 的转换正是由 RequestResponseBodyMethodProcessor 完成,ServletInvocableHandlerMethod 通过 supportsReturnType 方法决定 HandlerMethodReturnValueHandler 是否可以处理当前返回类型或返回方法,RequestResponseBodyMethodProcessor 的实现:
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return ((AnnotationUtils.findAnnotation(returnType.getContainingClass(), ResponseBody.class) != null) ||
(returnType.getMethodAnnotation(ResponseBody.class) != null));
}
核心的 handleReturnValue 方法:
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) {
mavContainer.setRequestHandled(true);
if (returnValue != null) {
writeWithMessageConverters(returnValue, returnType, webRequest);
}
}
这里其实是通过 HttpMessageConverter 的 canRead 或 canWrite 方法来判断给定的转换器是否合适,canWrite 方法实现:
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType));
}
这里剩下的便是 Jackson 的事情了,注意 MappingJacksonHttpMessageConverter 中的 objectMapper 被所有的线程所共享,因为其是线程安全的,但是这样是否有性能问题?
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论