当SpringMVC的Interceptor的后置方法遇到ResponseBody

之前遇到一个问题,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会把结果直接写回去了,这个时候请求响应已经完成了,我们拿的响应信息是没有经过拦截器的后置处理的。

推荐阅读更多精彩内容