简介
@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
处理器调用链,调用HandlerExecutionChain
的handle(...)
方法进行请求和响应等的处理。
· 调用HandlerExecutionChain
的applyPreHandle
、applyPostHandle
和triggerAfterCompletion
的方法,其对应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
注解,不进行处理直接返回。
· 若存在响应,且@ResponseStatus
的reason
属性不为空,则使用response.sendError(...)
响应请求。
· 若存在响应,且@ResponseStatus
的reason
属性为空,则使用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框架处理请求的必要骨架,本文之所以一起分析,是为了更好的说明处理逻辑。