41

Spring 中 HttpMessageConverter 的工作原理

 5 years ago
source link: https://mp.weixin.qq.com/s/-hwTV4a4D9SloH7w-UbxgA?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Y3IB7ru.jpg!web

在SpringMvc中,想要一个Http接口返回Json格式的数据,只需要在Controller类中做如下定义:

@GetMapping("/{id}")

public @ResponseBody Book findById(@PathVariable long id) {

return bookService.findById(id);

}

客户端在http请求头"Accept"设置成application/json:

curl --header "Accept: application/json"  http://localhost:8080/spring-boot-rest/books/1

Book class:

public class Book {

private long id;

private String name;

}

接口返回值如下:

{

"id": 1,

"name": "Thinking in Ja",

}

在http请求头中简单的设置一个Accept header,我们就可以从服务端获取想要的json格式,这是如何做到的,没错,是HttpMessageConverter实现的。

在Spring中,HttpMessageConverter是一个怎样的接口:

/**

* Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.

*

* @author Arjen Poutsma

* @author Juergen Hoeller

* @since 3.0

*/

public interface HttpMessageConverter<T> {

可以看出,它是工作在http request和response两者之间的一种策略,它关注的核心是:

如何从http请求中读http消息--读并且转

如何往http response中回写http消息--转并且写

3iQbum2.jpg!web

作为整个功能模块核心的接口,它暴露的可用操作很明确

截止到Spring4.3.9版本,已经内置了很多常用的消息格式转换器,如feed,atom,xml,json,protobuf,下面都是HttpMessageConverter的具体实现: eymM7bf.jpg!web

事实上,我们上边例子中转Json最终用到的是MappingJackson2HttpMessageConverter,来看下这个类的继承图

3ArYbaV.jpg!web

那么在http请求时,有了具体的转换工具,那么是谁来操作HttpMessageConverter来完成转换逻辑呢

在上面的例子中,我们使用了@ResponseBody, 那么在SpringMvc中,就要用到RequestResponseBodyMethodProcessor这个类来处理了,也就是完成从JavaBean转成Json再回写到http response中。

事实上这个RequestResponseBodyMethodProcessor类所能做的远不止此,它同样也可以处理@RequestBody的具体读取逻辑。

vEvEfar.jpg!web

从它的继续图可以看到两个SpringMvc中两个核心接口:

  1. HandlerMethodReturnValueHandler

  2. HandlerMethodArgumentResolver

前者总体负责处理Handler的返回值处理逻辑-对应http reponse的写

后者负责处理Handler参数的解析逻辑-对应http request的读

在SpringMvc中 一揽子Handler和ArguementResover通过组合模式被封装成一个整体,放到RequestMappingHandlerAdapter中,供SpringMvc直接用来处理http请求的读和写。

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter

implements BeanFactoryAware, InitializingBean {


private List<HandlerMethodArgumentResolver> customArgumentResolvers;


private HandlerMethodArgumentResolverComposite argumentResolvers;


private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;


private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;


private HandlerMethodReturnValueHandlerComposite returnValueHandlers;


对http请求参数的具体处理,交给了InvocableHandlerMethod.getMethodArgumentValues方法:

if (this.argumentResolvers.supportsParameter(parameter)) {

try {

args[i] = this.argumentResolvers.resolveArgument(

parameter, mavContainer, request, this.dataBinderFactory);

continue;

}

而对http返回值的处理,则是交给org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

try {

this.returnValueHandlers.handleReturnValue(

returnValue, getReturnValueType(returnValue), mavContainer, webRequest);

}

上述逻辑一起完成http请求的入口和出口的处理工作。

SpringAutowired

一个有用的公众号

Qjma6rB.jpg!web

长按,识别二维码,加关注


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK