接口定义:
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
该接口的主要职责是将某一java类实例转换为http的请求或者响应,这里主要看响应。其中两个canXxx方法定义了该converter是否可以处理当前响应。read以及write方法定义了具体的读写方法。
该类型的实例是如何被SpringMVC框架处理的?
AbstractMessageConverterMethodProcessor的抽象类实现了returnValueHandler以及arguementResolver接口,会在Adapter调用controller的前后被调用。这个类内部会持有一个HttpMessageConverter类型的List,逐个调用converter。所以这个类可以理解为一个桥梁,连接了RequestMappingAdapter以及HttpMessageConverter。
该抽象类有两个常见的实现类,一个是HttpEntityMethodProcessor,用于处理RequestEntity类型的返回值;另一个是RequestResponseBodyMethodProcessor,用于处理json类型的返回值。
以HttpEntityMethodProcessor处理二进制内容为例:
二进制数据会被ByteArrayHttpMessageConverter类型的converter处理。
该类继承自抽象类AbstractHttpMessageConverter。在AbstractHttpMessageConverter类中定义了一些公共的骨架方法。比如canXxx方法:
@Override
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
return supports(clazz) && canWrite(mediaType);
}
/**
* Returns {@code true} if the given media type includes any of the
* {@linkplain #setSupportedMediaTypes(List) supported media types}.
* @param mediaType the media type to write, can be {@code null} if not specified.
* Typically the value of an {@code Accept} header.
* @return {@code true} if the supported media types are compatible with the media type,
* or if the media type is {@code null}
*/
protected boolean canWrite(@Nullable MediaType mediaType) {
if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes()) {
if (supportedMediaType.isCompatibleWith(mediaType)) {
return true;
}
}
return false;
}
其中canWrite方法会根据MediaType判断是否执行。对于ByteArrayHttpMessageConverter来说,其所支持的MediaType为:
public ByteArrayHttpMessageConverter() {
super(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL);
}
也就是二进制类数据。
另一个抽象方法write方法:
@Override
public final void write(final T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
final HttpHeaders headers = outputMessage.getHeaders();
addDefaultHeaders(headers, t, contentType);
if (outputMessage instanceof StreamingHttpOutputMessage) {
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
@Override
public OutputStream getBody() {
return outputStream;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
}));
}
else {
writeInternal(t, outputMessage);
outputMessage.getBody().flush();
}
}
会调用writeInternal抽象方法,将数据写入httpResponse的body里。
仍然以ByteArrayHttpMessageConverter为例:
@Override
protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException {
StreamUtils.copy(bytes, outputMessage.getBody());
}
其writeInternal方法就是将二进制数组写入到body中。
类图: