一个请求在Spring中处理流程是有多种方式拦截处理的,而且,请求是可以拆分为进入和响应2个操作的,进入我们通常会对请求参数做处理,而响应我们通常会对响应参数做处理,Spring提供了多种方式给开发者。

一、HandlerInterceptor

我们写的controller,在Spring中被定义为handler,拦截controller的拦截器被定义为org.springframework.web.servlet.HandlerInterceptor。

拦截器的拦截逻辑是在org.springframework.web.servlet.DispatcherServlet中写的,需要注意的是,如果入口拦截顺序是a->b->c的话,那么出口拦截顺序是c->b->a,这个逻辑可以看org.springframework.web.servlet.HandlerExecutionChain里的一段逻辑。

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 {processedRequest = checkMultipart(request);multipartRequestParsed = (processedRequest != request);// Determine handler for the current request.mappedHandler = getHandler(processedRequest);if (mappedHandler == null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet = HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;}catch (Throwable err) {// As of 4.3, we're processing Errors thrown from handler methods as well,// making them available for @ExceptionHandler methods and other scenarios.dispatchException = new NestedServletException("Handler dispatch failed", err);}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}

这里能很清晰的看到循环使用的次序。

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i = 0; i = 0; i--) {HandlerInterceptor interceptor = this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}}

org.springframework.web.servlet.HandlerInterceptor

public interface HandlerInterceptor {/** * Interception point before the execution of a handler. Called after * HandlerMapping determined an appropriate handler object, but before * HandlerAdapter invokes the handler. * 

DispatcherServlet processes a handler in an execution chain, consisting * of any number of interceptors, with the handler itself at the end. * With this method, each interceptor can decide to abort the execution chain, * typically sending an HTTP error or writing a custom response. *

Note: special considerations apply for asynchronous * request processing. For more details see * {@link org.springframework.web.servlet.AsyncHandlerInterceptor}. *

The default implementation returns {@code true}. * @param request current HTTP request * @param response current HTTP response * @param handler chosen handler to execute, for type and/or instance evaluation * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. * @throws Exception in case of errors */default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {return true;}/** * Interception point after successful execution of a handler. * Called after HandlerAdapter actually invoked the handler, but before the * DispatcherServlet renders the view. Can expose additional model objects * to the view via the given ModelAndView. *

DispatcherServlet processes a handler in an execution chain, consisting * of any number of interceptors, with the handler itself at the end. * With this method, each interceptor can post-process an execution, * getting applied in inverse order of the execution chain. *

Note: special considerations apply for asynchronous * request processing. For more details see * {@link org.springframework.web.servlet.AsyncHandlerInterceptor}. *

The default implementation is empty. * @param request current HTTP request * @param response current HTTP response * @param handler the handler (or {@link HandlerMethod}) that started asynchronous * execution, for type and/or instance examination * @param modelAndView the {@code ModelAndView} that the handler returned * (can also be {@code null}) * @throws Exception in case of errors */default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}/** * Callback after completion of request processing, that is, after rendering * the view. Will be called on any outcome of handler execution, thus allows * for proper resource cleanup. *

Note: Will only be called if this interceptor's {@code preHandle} * method has successfully completed and returned {@code true}! *

As with the {@code postHandle} method, the method will be invoked on each * interceptor in the chain in reverse order, so the first interceptor will be * the last to be invoked. *

Note: special considerations apply for asynchronous * request processing. For more details see * {@link org.springframework.web.servlet.AsyncHandlerInterceptor}. *

The default implementation is empty. * @param request current HTTP request * @param response current HTTP response * @param handler the handler (or {@link HandlerMethod}) that started asynchronous * execution, for type and/or instance examination * @param ex any exception thrown on handler execution, if any; this does not * include exceptions that have been handled through an exception resolver * @throws Exception in case of errors */default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}

二、HandlerMethodArgumentResolver

上面的HandlerInterceptor可以清楚的看到接收的参数是HttpServletRequest,这是最早期的参数,紧接着Spring会从HttpServletRequest里把参数读取到controller定义的请求参数里面,此时用到的类型是HttpMessageConverter,他把参数写入controller中,此时是可以在参数写入前后做一些操作的。

三、RequestBodyAdvice

org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice

org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice

这2个可以直接修改请求参数,可以看到写入之后,就得到了controller定义的参数类型。

public interface RequestBodyAdvice {/** * Invoked first to determine if this interceptor applies. * @param methodParameter the method parameter * @param targetType the target type, not necessarily the same as the method * parameter type, e.g. for {@code HttpEntity}. * @param converterType the selected converter type * @return whether this interceptor should be invoked or not */boolean supports(MethodParameter methodParameter, Type targetType,Class<? extends HttpMessageConverter> converterType);/** * Invoked second before the request body is read and converted. * @param inputMessage the request * @param parameter the target method parameter * @param targetType the target type, not necessarily the same as the method * parameter type, e.g. for {@code HttpEntity}. * @param converterType the converter used to deserialize the body * @return the input request or a new instance (never {@code null}) */HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter> converterType) throws IOException;/** * Invoked third (and last) after the request body is converted to an Object. * @param body set to the converter Object before the first advice is called * @param inputMessage the request * @param parameter the target method parameter * @param targetType the target type, not necessarily the same as the method * parameter type, e.g. for {@code HttpEntity}. * @param converterType the converter used to deserialize the body * @return the same body or a new instance */Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter> converterType);/** * Invoked second (and last) if the body is empty. * @param body usually set to {@code null} before the first advice is called * @param inputMessage the request * @param parameter the method parameter * @param targetType the target type, not necessarily the same as the method * parameter type, e.g. for {@code HttpEntity}. * @param converterType the selected converter type * @return the value to use, or {@code null} which may then raise an * {@code HttpMessageNotReadableException} if the argument is required */@NullableObject handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,Type targetType, Class<? extends HttpMessageConverter> converterType);}
public interface ResponseBodyAdvice {/** * Whether this component supports the given controller method return type * and the selected {@code HttpMessageConverter} type. * @param returnType the return type * @param converterType the selected converter type * @return {@code true} if {@link #beforeBodyWrite} should be invoked; * {@code false} otherwise */boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter> converterType);/** * Invoked after an {@code HttpMessageConverter} is selected and just before * its write method is invoked. * @param body the body to be written * @param returnType the return type of the controller method * @param selectedContentType the content type selected through content negotiation * @param selectedConverterType the converter type selected to write to the response * @param request the current request * @param response the current response * @return the body that was passed in or a modified (possibly new) instance */@NullableT beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,Class<? extends HttpMessageConverter> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response);}

四、整体时序

HandlerInterceptor preHandle ->
RequestBodyAdvice ->
HandlerMethodArgumentResolver ->
RequestBodyAdvice ->
controller ->
AOP afterReturning ->
ResponseBodyAdvice beforeBodyWrite ->
HttpMessageConverter(转JSON )->
HandlerInterceptor postHandle ->
HandlerInterceptor afterCompletion