简介

  @ResponseStatus注解可以应用在两种应用场景下:

  ① @ResponseStatus注释控制器类或方法,@ResponseStatus注解的属性用来为响应设置状态代码和状态原因。

  ② @ResponseStatus注释异常类,用来解析指定类型异常,@ResponseStatus注解的属性用来为响应设置状态代码和状态原因。

  接下来对第一种场景下@ResponseStatus的处理逻辑进行分析。

  @ResponseStatus注释控制器类或方法

  ① 主要调用流程。

DispatcherServlet.doDispatch(...) -- 调用 -->
AbstractHandlerMethodAdapter.handle(...) -- 调用 -->
RequestMappingHandlerAdapter.handleInternal(...) -- 调用 -->
RequestMappingHandlerAdapter.invokeHandlerMethod(...) -- 调用 -->
ServletInvocableHandlerMethod.invokeAndHandle(...) -- 调用 -->
ServletInvocableHandlerMethod.setResponseStatus(...) -- 调用 -->
ServletInvocableHandlerMethod.setResponseStatus(...)内部实现对@ResponseStatus注解的处理.

  以上是从DispatcherServlet开始,请求到达Web容器时,经过前面逻辑处理后,进行对@ResponseStatus注解的处理。

  ② DispatcherServlet.doDispatch(...)是Spring MVC请求接入点。

  · 主要用来调用初始化HandlerExecutionChain处理器调用链,调用HandlerExecutionChainhandle(...)方法进行请求和响应等的处理。

  · 调用HandlerExecutionChainapplyPreHandleapplyPostHandletriggerAfterCompletion的方法,其对应HandlerInterceptor拦截器的preHandle(...)postHandle(...)afterCompletion(...)方法,完成对处理器的拦截处理。

/**
 * 分发请求给处理程序.
 * 处理程序将按照顺序处理Servlet的HandlerMappings.
 * HandlerAdapter将通过查询Servlet已配置的HandlerAdapter来获取,以找到第一个支持handler类的HandlerAdapter.
 * 所有的HTTP方法都由这个方法处理.
 * 由HandlerAdapter或处理程序自己决定哪些方法是可接受的.
 * @param request 当前请求实例.
 * @param response 当前响应实例.
 * @throws Exception .
 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    // 处理器执行链.
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // 确认是否multipart/form-data请求.
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 获得当前请求的处理器.
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 获取当前请求的处理器适配器.
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 处理last-modified请求头.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            // 调用处理器的applyPreHandle方法.
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 实际调用处理器方法处理请求.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            // 处理默认视图.
            applyDefaultViewName(processedRequest, mv);
            // 调用处理器的applyPostHandle方法.
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // 从4.3开始,同时会处理从handler方法抛出的错误,使它们可以用于@ExceptionHandler方法和其他场景.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 处理转发结果.
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        // 调用处理器的triggerAfterCompletion方法.
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // 调用处理器的triggerAfterCompletion方法.
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // 代替postHandle和afterCompletion.
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // 清除multipart/form-data请求使用的所有资源.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

  ③ AbstractHandlerMethodAdapter.handle(...)是抽象定义,采用模板方法设计模式调用子类的handleInternal(...)方法。

/**
 * 此实现要求处理程序是HandlerMethod.
 */
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {

    return handleInternal(request, response, (HandlerMethod) handler);
}

  ④ RequestMappingHandlerAdapter.handleInternal(...)是处理器适配器的内部处理。

  ·HttpSession进行处理,避免多线程对程序带来的影响。

  · 对响应Cache-Control头进行处理。

/**
 * 内部处理方法.
 */
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
                                      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ModelAndView mav;
    // 检查给定的请求以获得支持的方法和所需的会话(如果有).
    checkRequest(request);

    // 如果需要,在synchronized块中执行invokeHandlerMethod.
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        // 有HttpSession可用->需要互斥.
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // 没有HttpSession可用->不需要互斥.
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // 根本不需要会话同步.
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    // 响应头中不包含Cache-Control头.进行缓存处理.
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            prepareResponse(response);
        }
    }

    return mav;
}

  ⑤ RequestMappingHandlerAdapter.invokeHandlerMethod(...)是调用处理器的初始化工作,对处理器所需的信息进行设置。

/**
 * 如果需要视图解析,则调用RequestMapping处理程序方法准备ModelAndView.
 */
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    // 包装请求实例.
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 获取WebDataBinderFactory实例.
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 获取ModelFactory实例.
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        // 从给定的HandlerMethod定义创建ServletInvocableHandlerMethod.
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 设置参数解析器.
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 设置返回值解析器.
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 设置WebDataBinderFactory.
        invocableMethod.setDataBinderFactory(binderFactory);
        // 设置参数名称发现器.
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        // ModelAndView容器.
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // 设置属性.
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 初始化数据.
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        // 设置重定向时忽略默认数据.
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        // 设置异步请求超时时间.
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
        // 异步请求管理器.
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        // 设置拦截器.
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        // 设置结果拦截器.
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
        // 异步结果处理.
        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();
            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            // ServletInvocableHandlerMethod包装.
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }
        // 调用和处理请求.
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
        // 获取ModelAndView.
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

  ⑥ ServletInvocableHandlerMethod.invokeAndHandle(...)是具体的处理器调用发起点。

  · 调用具体处理器方法。

  · 处理@ResponseStatus注解。

  · 使用返回值处理器HandlerMethodReturnValueHandlerComposite处理返回值。

/**
 * 调用方法并通过配置的HandlerMethodReturnValueHandler处理返回值.
 * @param webRequest 当前请求实例.
 * @param mavContainer 请求的ModelAndViewContainer.
 * @param providedArgs 与类型匹配的给定参数(未解析).
 */
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
    // 调用方法请求并获取返回值.
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 设置响应状态.
    setResponseStatus(webRequest);
    // 返回值为空.
    if (returnValue == null) {
        // 1.请求是否满足"未被修改"条件.
        // 2.@ResponseStatus设置的响应状态代码不为空.
        // 3.请求是否已在处理程序中完全处理.
        // 满足以上三个条件,设置请求已处理完成,直接返回.
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    // @ResponseStatus设置的响应状态原因不为空,设置请求已处理完成,直接返回.
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }
    // 设置请求未处理完成.
    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 调用HandlerMethodReturnValueHandlerComposite处理返回值.
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
        }
        throw ex;
    }
}

  ⑦ ServletInvocableHandlerMethod.setResponseStatus(...)@ResponseStatus注解具体解析的方法。

  · 若无@ResponseStatus注解,不进行处理直接返回。

  · 若存在响应,且@ResponseStatusreason属性不为空,则使用response.sendError(...)响应请求。

  · 若存在响应,且@ResponseStatusreason属性为空,则使用response.setStatus(...)响应请求。

/**
 * 根据@ResponseStatus注解设置响应状态.
 */
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
    // 获取@ResponseStatus注解的code属性.
    HttpStatus status = getResponseStatus();
    if (status == null) {
        return;
    }
    // 获取请求响应.
    HttpServletResponse response = webRequest.getResponse();
    if (response != null) {
        // 获取@ResponseStatus注解的reason属性.
        String reason = getResponseStatusReason();
        // 若@ResponseStatus注解的reason属性不为空,则调用response.sendError(...)进行响应.
        if (StringUtils.hasText(reason)) {
            response.sendError(status.value(), reason);
        }
        // 若@ResponseStatus注解的reason属性为空,则调用response.setStatus(...)进行响应.
        else {
            response.setStatus(status.value());
        }
    }

    // 由RedirectView获取.
    webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}

  总结

  @ResponseStatus是一个简单的注解,从整体来看处理逻辑,刨除ServletInvocableHandlerMethod.setResponseStatus(...)之外,其他都属于上层处理逻辑,是Spring MVC框架处理请求的必要骨架,本文之所以一起分析,是为了更好的说明处理逻辑。