springboot源码分析:关于HttpMessageConverter原理的分析

Scroll Down

AbstractMessageConverterMethodArgumentResolver的介绍

这里使用这个类来引入是不准确的需要修改
该类的结构如下:
image.png
这个类的处理流程如下:

/**
 * Create the method argument value of the expected parameter type by reading
 * from the given HttpInputMessage.
 * @param <T> the expected type of the argument value to be created
 * @param inputMessage the HTTP input message representing the current request
 * @param parameter the method parameter descriptor
 * @param targetType the target type, not necessarily the same as the method
 * parameter type, e.g. for {@code HttpEntity<String>}.
 * @return the created method argument value
 * @throws IOException if the reading from the request fails
 * @throws HttpMediaTypeNotSupportedException if no suitable message converter is found
 */
@SuppressWarnings("unchecked")
@Nullable
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
			Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {

	MediaType contentType;
	boolean noContentType = false;
	try {
		// 从request的Headers中获取Content-type内容。
		contentType = inputMessage.getHeaders().getContentType();
	}
	catch (InvalidMediaTypeException ex) {
		throw new HttpMediaTypeNotSupportedException(ex.getMessage());
	}
	if (contentType == null) {
		noContentType = true;
		// 如果contentType为空,则默认使用二进制的APPLICATION_OCTET_STREAM
		contentType = MediaType.APPLICATION_OCTET_STREAM;
	}
	// 获取Controller的类型。
	Class<?> contextClass = parameter.getContainingClass();
	// 转化的目标类型。
	Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
	if (targetClass == null) {
		ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
		targetClass = (Class<T>) resolvableType.resolve();
	}
	// 获取请求方式。
	HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
	Object body = NO_VALUE;

	EmptyBodyCheckingHttpInputMessage message;
	try {
		message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
		// 从messageConverters中循环遍历是否存在支持转换的Converter,将转化之后的结果返回。
		for (HttpMessageConverter<?> converter : this.messageConverters) {
			Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
			GenericHttpMessageConverter<?> genericConverter =
						(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
			// 如果converter符合调用条件,则执行转换操作。
			if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
						(targetClass != null && converter.canRead(targetClass, contentType))) {
				if (message.hasBody()) {
					HttpInputMessage msgToUse =
								getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
					// 调用converter的read方法将字符串转成对应的对象。
					body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
								((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
					body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
				}
				else {
					body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
				}
				break;
			}
		}
	}
	catch (IOException ex) {
		throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
	}

	if (body == NO_VALUE) {
		if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
					(noContentType && !message.hasBody())) {
			return null;
		}
		throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
	}

	MediaType selectedContentType = contentType;
	Object theBody = body;
	LogFormatUtils.traceDebug(logger, traceOn -> {
		String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
		return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
	});

	return body;
}

上面就是转换器的工作的入口。

/**
 * Invoke the method and handle the return value through one of the
 * configured {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers}.
 * @param webRequest the current request
 * @param mavContainer the ModelAndViewContainer for this request
 * @param providedArgs "given" arguments matched by type (not resolved)
 */
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	setResponseStatus(webRequest);

	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			disableContentCachingIfNecessary(webRequest);
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	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;
	}
}

/**
 * Iterate over registered {@link HandlerMethodReturnValueHandler HandlerMethodReturnValueHandlers} and invoke the one that supports it.
 * @throws IllegalStateException if no suitable {@link HandlerMethodReturnValueHandler} is found.
 */
@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);
}

@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.
	// 这里会调用HttpMessageConverter的write操作。
	writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

writeWithMessageConverters方法如下:

/**
 * Writes the given return type to the given output message.
 * @param value the value to write to the output message
 * @param returnType the type of the value
 * @param inputMessage the input messages. Used to inspect the {@code Accept} header.
 * @param outputMessage the output message to write to
 * @throws IOException thrown in case of I/O errors
 * @throws HttpMediaTypeNotAcceptableException thrown when the conditions indicated
 * by the {@code Accept} header on the request cannot be met by the message converters
 * @throws HttpMessageNotWritableException thrown if a given message cannot
 * be written by a converter, or if the content-type chosen by the server
 * has no compatible converter.
 */
@SuppressWarnings({"rawtypes", "unchecked"})
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
			ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

	Object body;
	Class<?> valueType;
	Type targetType;

	if (value instanceof CharSequence) {
		body = value.toString();
		valueType = String.class;
		targetType = String.class;
	}
	else {
		body = value;
		valueType = getReturnValueType(body, returnType);
		targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
	}

	if (isResourceType(value, returnType)) {
		outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
		if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
					outputMessage.getServletResponse().getStatus() == 200) {
			Resource resource = (Resource) value;
			try {
				List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
				outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
				body = HttpRange.toResourceRegions(httpRanges, resource);
				valueType = body.getClass();
				targetType = RESOURCE_REGION_LIST_TYPE;
			}
			catch (IllegalArgumentException ex) {
				outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
				outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
			}
		}
	}

	MediaType selectedMediaType = null;
	MediaType contentType = outputMessage.getHeaders().getContentType();
	boolean isContentTypePreset = contentType != null && contentType.isConcrete();
	if (isContentTypePreset) {
		if (logger.isDebugEnabled()) {
			logger.debug("Found 'Content-Type:" + contentType + "' in response");
		}
		selectedMediaType = contentType;
	}
	else {
		HttpServletRequest request = inputMessage.getServletRequest();
		List<MediaType> acceptableTypes = getAcceptableMediaTypes(request);
		List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);

		if (body != null && producibleTypes.isEmpty()) {
			throw new HttpMessageNotWritableException(
						"No converter found for return value of type: " + valueType);
		}
		List<MediaType> mediaTypesToUse = new ArrayList<>();
		for (MediaType requestedType : acceptableTypes) {
			for (MediaType producibleType : producibleTypes) {
				if (requestedType.isCompatibleWith(producibleType)) {
					mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
				}
			}
		}
		if (mediaTypesToUse.isEmpty()) {
			if (body != null) {
				throw new HttpMediaTypeNotAcceptableException(producibleTypes);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
			}
			return;
		}

		MediaType.sortBySpecificityAndQuality(mediaTypesToUse);

		for (MediaType mediaType : mediaTypesToUse) {
			if (mediaType.isConcrete()) {
				selectedMediaType = mediaType;
				break;
			}
			else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
				selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
				break;
			}
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Using '" + selectedMediaType + "', given " +
						acceptableTypes + " and supported " + producibleTypes);
		}
	}

	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)) {
				body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
							(Class<? extends HttpMessageConverter<?>>) converter.getClass(),
							inputMessage, outputMessage);
				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);
					}
				}
				else {
					if (logger.isDebugEnabled()) {
						logger.debug("Nothing to write: null body");
					}
				}
				return;
			}
		}
	}

	if (body != null) {
		Set<MediaType> producibleMediaTypes =
					(Set<MediaType>) inputMessage.getServletRequest()
							.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

		if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {
			throw new HttpMessageNotWritableException(
						"No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");
		}
		throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
	}
}

有些类需要同时支持参数的解析和参数的写入操作比如HttpEntityMethodProcessor和RequestResponseBodyMethodProcessor所以它们会同时具有readWithMessageConverters和writeWithMessageConverters两个方法。
类的结构图如下
image.png
具体则是根据解析及写入对象的需求来决定的。
这里会详细分析下HttpMessageConverter的工作原理

HttpMessageConverter的工作原理

SpringMVC在初始化的时候自动注册了一些转换器,代码如下:

/**
 * Returns a {@link RequestMappingHandlerAdapter} for processing requests
 * through annotated controller methods. Consider overriding one of these
 * other more fine-grained methods:
 * <ul>
 * <li>{@link #addArgumentResolvers} for adding custom argument resolvers.
 * <li>{@link #addReturnValueHandlers} for adding custom return value handlers.
 * <li>{@link #configureMessageConverters} for adding custom message converters.
 * </ul>
 */
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
			@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
			@Qualifier("mvcConversionService") FormattingConversionService conversionService,
			@Qualifier("mvcValidator") Validator validator) {

	RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
	adapter.setContentNegotiationManager(contentNegotiationManager);
	// 在这里注册了默认的MessageConverters
	adapter.setMessageConverters(getMessageConverters());
	adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
	adapter.setCustomArgumentResolvers(getArgumentResolvers());
	adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

	if (jackson2Present) {
		adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
		adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
	}

	AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
	configureAsyncSupport(configurer);
	if (configurer.getTaskExecutor() != null) {
		adapter.setTaskExecutor(configurer.getTaskExecutor());
	}
	if (configurer.getTimeout() != null) {
		adapter.setAsyncRequestTimeout(configurer.getTimeout());
	}
	adapter.setCallableInterceptors(configurer.getCallableInterceptors());
	adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

	return adapter;
}

/**
 * Provides access to the shared {@link HttpMessageConverter HttpMessageConverters}
 * used by the {@link RequestMappingHandlerAdapter} and the
 * {@link ExceptionHandlerExceptionResolver}.
 * <p>This method cannot be overridden; use {@link #configureMessageConverters} instead.
 * Also see {@link #addDefaultHttpMessageConverters} for adding default message converters.
 */
protected final List<HttpMessageConverter<?>> getMessageConverters() {
	if (this.messageConverters == null) {
		this.messageConverters = new ArrayList<>();
		configureMessageConverters(this.messageConverters);
		if (this.messageConverters.isEmpty()) {
		// 注册默认的HttpMessageConverters
		addDefaultHttpMessageConverters(this.messageConverters);
		}
		extendMessageConverters(this.messageConverters);
	}
	return this.messageConverters;
}

/**
 * Adds a set of default HttpMessageConverter instances to the given list.
 * Subclasses can call this method from {@link #configureMessageConverters}.
 * @param messageConverters the list to add the default message converters to
 */
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
	messageConverters.add(new ByteArrayHttpMessageConverter());
	messageConverters.add(new 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()));
	}
}

所有的转换器都来自同一个实现接口HttpMessageConverter,该接口的内容如下:
image.png
(1)、canRead:判断一个给定的类型和请求类型是否可以进行读取。比如JSON -> Object

/**
 * Indicates whether the given class can be read by this converter.
 * @param clazz the class to test for readability
 * @param mediaType the media type to read (can be {@code null} if not specified);
 * typically the value of a {@code Content-Type} header.
 * @return {@code true} if readable; {@code false} otherwise
 */
boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

(2)、canWrite:判断一个给定的类型和请求类型是否可以进行写入。比如Object -> JSON

/**
 * Indicates whether the given class can be written by this converter.
 * @param clazz the class to test for writability
 * @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 writable; {@code false} otherwise
 */
boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

(3)、getSupportedMediaTypes:获取支持的MediaTypes。

/**
 * Return the list of {@link MediaType} objects supported by this converter.
 * @return the list of supported media types, potentially an immutable copy
 */
List<MediaType> getSupportedMediaTypes();

(4)、read:执行读取操作。从某个InputStream中读取数据并将数据转成T

/**
 * Read an object of the given type from the given input message, and returns it.
 * @param clazz the type of object to return. This type must have previously been passed to the
 * {@link #canRead canRead} method of this interface, which must have returned {@code true}.
 * @param inputMessage the HTTP input message to read from
 * @return the converted object
 * @throws IOException in case of I/O errors
 * @throws HttpMessageNotReadableException in case of conversion errors
 */
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException;

(5)、write:执行写入操作,将数据T写入到某个OutputStream

/**
 * Write an given object to the given output message.
 * @param t the object to write to the output message. The type of this object must have previously been
 * passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
 * @param contentType the content type to use when writing. May be {@code null} to indicate that the
 * default content type of the converter must be used. If not {@code null}, this media type must have
 * previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
 * returned {@code true}.
 * @param outputMessage the message to write to
 * @throws IOException in case of I/O errors
 * @throws HttpMessageNotWritableException in case of conversion errors
 */
void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException;

HttpMessageConverter这个接口还有一个子接口GenericHttpMessageConverter用于处理部分解析存在泛型的情况。目前使用的JSON解析器就是使用了这个接口来进行实现。
接下来逐个说明下实现类的原理:

(1)、ByteArrayHttpMessageConverter

该类负责读取二进制格式的数据和写出二进制格式的数据。
该类的构造函数如下:

/**
 * Create a new instance of the {@code ByteArrayHttpMessageConverter}.
 */
public ByteArrayHttpMessageConverter() {
	super(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL);
}

会调用父类AbstractHttpMessageConverter的构造函数。

/**
 * Construct an {@code AbstractHttpMessageConverter} with multiple supported media types.
 * @param supportedMediaTypes the supported media types
 */
protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) {
	setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
}

/**
 * Set the list of {@link MediaType} objects supported by this converter.
 */
public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
	Assert.notEmpty(supportedMediaTypes, "MediaType List must not be empty");
	this.supportedMediaTypes = new ArrayList<>(supportedMediaTypes);
}

在创建该类的对象的时候会注册MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL这两个类型,表明该类支持这两种类型的数据的读取和写入。
读操作如下:

canRead方法

/**
 * This implementation checks if the given class is {@linkplain #supports(Class) supported},
 * and if the {@linkplain #getSupportedMediaTypes() supported media types}
 * {@linkplain MediaType#includes(MediaType) include} the given media type.
 */
@Override
public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
	// supports在子类中进行覆盖
	return supports(clazz) && canRead(mediaType);
}

@Override
public boolean supports(Class<?> clazz) {
	// 判断参数类型是否是byte[]
	return byte[].class == clazz;
}

/**
 * Returns {@code true} if any of the {@linkplain #setSupportedMediaTypes(List)
 * supported} media types {@link MediaType#includes(MediaType) include} the
 * given media type.
 * @param mediaType the media type to read, can be {@code null} if not specified.
 * Typically the value of a {@code Content-Type} header.
 * @return {@code true} if the supported media types include the media type,
 * or if the media type is {@code null}
 */
protected boolean canRead(@Nullable MediaType mediaType) {
	// 如果为null则表示该转换器不用必须需要mediaType。
	if (mediaType == null) {
		return true;
	}
	// 判断该mediaType是否在该转换器的支持的类型列表中。也就是MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL这两个类型。
	for (MediaType supportedMediaType : getSupportedMediaTypes()) {
		if (supportedMediaType.includes(mediaType)) {
			return true;
		}
	}
	return false;
}

读取操作如下:

/**
 * This implementation simple delegates to {@link #readInternal(Class, HttpInputMessage)}.
 * Future implementations might add some default behavior, however.
 */
@Override
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException {
	// 抽象方法,子类提供实现。
	return readInternal(clazz, inputMessage);
}

@Override
public byte[] readInternal(Class<? extends byte[]> clazz, HttpInputMessage inputMessage) throws IOException {
	// 获取数据长度
	long contentLength = inputMessage.getHeaders().getContentLength();
	// 使用ByteArrayOutputStream来读取inputMessage中的数据。
	ByteArrayOutputStream bos =
				new ByteArrayOutputStream(contentLength >= 0 ? (int) contentLength : StreamUtils.BUFFER_SIZE);
		StreamUtils.copy(inputMessage.getBody(), bos);
	return bos.toByteArray();
}

写操作如下:

/**
 * This implementation checks if the given class is
 * {@linkplain #supports(Class) supported}, and if the
 * {@linkplain #getSupportedMediaTypes() supported} media types
 * {@linkplain MediaType#includes(MediaType) include} the given media type.
 */
@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;
}

write方法:

/**
 * This implementation sets the default headers by calling {@link #addDefaultHeaders},
 * and then calls {@link #writeInternal}.
 */
@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();
	}
}

@Override
protected void writeInternal(byte[] bytes, HttpOutputMessage outputMessage) throws IOException {
	// 将bytes写入到output中。
	StreamUtils.copy(bytes, outputMessage.getBody());
}

(2)、StringHttpMessageConverter

与byte操作一致,不过只是类型换成String。

@Override
public boolean supports(Class<?> clazz) {
	// 判断转换的参数类型是否是String。
	return String.class == clazz;
}

读取操作:

@Override
protected String readInternal(Class<? extends String> clazz, HttpInputMessage inputMessage) throws IOException {
	// 获取字符集
	Charset charset = getContentTypeCharset(inputMessage.getHeaders().getContentType());
	// 从body中获取String数据。
	return StreamUtils.copyToString(inputMessage.getBody(), charset);
}

写入操作:

@Override
protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
	HttpHeaders headers = outputMessage.getHeaders();
	if (this.writeAcceptCharset && headers.get(HttpHeaders.ACCEPT_CHARSET) == null) {
		headers.setAcceptCharset(getAcceptedCharsets());
	}
	// 获取字符集
	Charset charset = getContentTypeCharset(headers.getContentType());
	// 将字符串写入到OutputStream中。
	StreamUtils.copy(str, charset, outputMessage.getBody());
}

(3)、MappingJackson2XmlHttpMessageConverter

XML解析器。
与JSON解析器一起说明。

(4)、MappingJackson2HttpMessageConverter

JSON解析器。
XML和JSON解析器同样都使用了同一个父类来进行读取和写入操作的。
判断是否可以读取操作如下:

@Override
public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
	return canRead(clazz, null, mediaType);
}

@Override
public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
	if (!canRead(mediaType)) {
		return false;
	}
	// 获取需要转成的java类
	JavaType javaType = getJavaType(type, contextClass);
	AtomicReference<Throwable> causeRef = new AtomicReference<>();
	// 使用Jackson的类来判断是否可以序列化。
	if (this.objectMapper.canDeserialize(javaType, causeRef)) {
		return true;
	}
	logWarningIfNecessary(javaType, causeRef.get());
		return false;
}

执行读取操作:

@Override
public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
			throws IOException, HttpMessageNotReadableException {

	JavaType javaType = getJavaType(type, contextClass);
	// 执行JSON字符串->obj的过程。
	return readJavaType(javaType, inputMessage);
}

判断是否可以写入操作:

@Override
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
	if (!canWrite(mediaType)) {
		return false;
	}
	AtomicReference<Throwable> causeRef = new AtomicReference<>();
	if (this.objectMapper.canSerialize(clazz, causeRef)) {
		return true;
	}
	logWarningIfNecessary(clazz, causeRef.get());
	return false;
}

执行写入操作:

@Override
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
			throws IOException, HttpMessageNotWritableException {

	MediaType contentType = outputMessage.getHeaders().getContentType();
	JsonEncoding encoding = getJsonEncoding(contentType);
	JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
	try {
		writePrefix(generator, object);

		Object value = object;
		Class<?> serializationView = null;
		FilterProvider filters = null;
		JavaType javaType = null;

		if (object instanceof MappingJacksonValue) {
			MappingJacksonValue container = (MappingJacksonValue) object;
			value = container.getValue();
			serializationView = container.getSerializationView();
			filters = container.getFilters();
		}
		if (type != null && TypeUtils.isAssignable(type, value.getClass())) {
			javaType = getJavaType(type, null);
		}

		ObjectWriter objectWriter = (serializationView != null ?
					this.objectMapper.writerWithView(serializationView) : this.objectMapper.writer());
		if (filters != null) {
			objectWriter = objectWriter.with(filters);
		}
		if (javaType != null && javaType.isContainerType()) {
			objectWriter = objectWriter.forType(javaType);
		}
		SerializationConfig config = objectWriter.getConfig();
		if (contentType != null && contentType.isCompatibleWith(MediaType.TEXT_EVENT_STREAM) &&
					config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
			objectWriter = objectWriter.with(this.ssePrettyPrinter);
		}
		// 执行obj->json的操作。
		objectWriter.writeValue(generator, value);

		writeSuffix(generator, object);
		generator.flush();
	}
	catch (InvalidDefinitionException ex) {
		throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
	}
	catch (JsonProcessingException ex) {
		throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getOriginalMessage(), ex);
	}
}