springmvc是如何对返回值进行响应的,控制器如何区分返回的是json数据or视图。实现这个过程主要依靠的是返回值处理器HandlerMethodReturnValueHandler,HandlerMethodReturnValueHandler是接口,
supportsReturnType:判断返回值类型当前处理器是否能处理
handleReturnValue:如果当前处理器支持处理这个类型,将会调用这个方法对返回值进行处理
public interface HandlerMethodReturnValueHandler {
/**
* Whether the given {@linkplain MethodParameter method return type} is
* supported by this handler.
* @param returnType the method return type to check
* @return {@code true} if this handler supports the supplied return type;
* {@code false} otherwise
*/
boolean supportsReturnType(MethodParameter returnType);
/**
* Handle the given return value by adding attributes to the model and
* setting a view or setting the
* {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
* to indicate the response has been handled directly.
* @param returnValue the value returned from the handler method
* @param returnType the type of the return value. This type must have
* previously been passed to {@link #supportsReturnType} which must
* have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @throws Exception if the return value handling results in an error
*/
void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
ServletInvocableHandlerMethod:对目标方法的调用最终都会被包装成ServletInvocableHandlerMethod对象进行方法调用
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 调用目标controller方法,returnValue就是controller的返回值
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;
}
}
ServletInvocableHandlerMethod对象中维护着容器着已经存在的处理器
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
HandlerMethodReturnValueHandlerComposite运用了组合的设计模式,会委托给具体的返回值处理器,每个返回值处理器会根据返回值类型自行判断是否支持处理返回值
// 自身实现了HandlerMethodReturnValueHandler接口,同时内部维护着一个处理器列表,委托给具体的处理器进行处理
public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodReturnValueHandler {
// 处理器列表
private final List<HandlerMethodReturnValueHandler> returnValueHandlers = new ArrayList<>();
/**
* Return a read-only list with the registered handlers, or an empty list.
*/
public List<HandlerMethodReturnValueHandler> getHandlers() {
return Collections.unmodifiableList(this.returnValueHandlers);
}
/**
* Whether the given {@linkplain MethodParameter method return type} is supported by any registered
* {@link HandlerMethodReturnValueHandler}.
*/
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return getReturnValueHandler(returnType) != null;
}
// 遍历所有的返回值处理器,选择一个能支持的进行返回处理
@Nullable
private HandlerMethodReturnValueHandler getReturnValueHandler(MethodParameter returnType) {
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}
/**
* 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);
}
}
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor
public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver
implements HandlerMethodReturnValueHandler
如上图所示RequestResponseBodyMethodProcessor继承AbstractMessageConverterMethodProcessor,最终实现了HandlerMethodReturnValueHandler,所以RequestResponseBodyMethodProcessor有能力去处理返回值,RequestResponseBodyMethodProcessor
判断2点,满足一下两点之一,表明支持处理该返回值
- 参数所在类上有没有
@ResponseBody注解 - 参数所在方法上或返回值上是否标注了
@ResponseBody注解
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
使用该处理器处理返回值
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
// 设置请求已被处理
// ModelAndViewContainer中有个requestHandled字段用来标识请求是否被处理
mavContainer.setRequestHandled(true);
// 将原始的请求对象包装为ServletServerHttpRequest
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
// 将原始的响应对象包装为ServletServerHttpResponse
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
// 将返回值写入响应体输出流中
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
writeWithMessageConverters 会调用messageConverter将消息转化成指定的格式
public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T> {
/**
* Indicates whether the given type can be read by this converter.
*/
boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType);
/**
* Read an object of the given type form the given input message, and returns it.
*/
T read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/**
* Indicates whether the given class can be written by this converter.
*/
boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType);
/**
* Write an given object to the given output message.
*/
void write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
最后选择MappingJackson2HttpMessageConverter将输出转化成json字符串写入到输出流中返回
public class MappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter
总结: 1.dispatchServlert会将调用的方法包装成ServletInvocableHandlerMethod对象进行调用
2.调用的结果选择合适的返回值处理器HandlerMethodReturnValueHandler处理
3.由于使用了responsebody注解,所以RequestResponseBodyMethodProcessor处理可以处理返回值
4.RequestResponseBodyMethodProcessor内部使用messageConverter进行处理,将数据返回。
这就是加上一个responsebody注解就能返回json的原因。
接下来会聊一聊
1:内容协商的过程
2:视图解析的过程
3:本文并没有对messageConverter进行仔细的讲解,后续会展开如何借助jackson将json返回前端