之前遇到一个问题,controller使用了ResponseBody注解,在spring mvc的Interceptor的postHandle方法中的处理逻辑不起作用,这个问题当时迷惑了很久。
今天在翻看spring mvc的源码的时候,找到了问题的答案。
当一个请求请求到spring mvc的时候,处理的流程是:
Listener->Filter->DispatcherServlet->getHandler->getHandlerAdaptor->拦截器前置处理->handler调用->拦截器后置处理->其他
正常的流程是这样的,但是当我们的方法上加上@ResponseBody注解的时候,变得不一样了,在handler调用的过程中,经过反射拿到了返回值,这个时候,由于spring mvc支持多种ReturnValue,此时org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite#handleReturnValue登场,要对结果进行处理
public void handleReturnValue(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);
}
这个时候根据ReturnValue和ReturnType选定合适的HandlerMethodReturnValueHandler,当我们的响应结果上面加上@ResponseBody的时候,org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor#supportsReturnType这个接口可以满足我们的需求
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
于是使用RequestResponseBodyMethodProcessor来处理我们的返回结果,
@Override
public void handleReturnValue(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.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
这段程序的最后一行,我们可以看到ServletServerHttpResponse会把结果直接写回去了,这个时候请求响应已经完成了,我们拿的响应信息是没有经过拦截器的后置处理的。