一、拦截器介绍
拦截器可以在进入请求方法前做一些操作,也可以在请求方法后和渲染视图后做一些事情。拦截器的实现只需要实现 HandlerInterceptor 接口,并进行配置即可。
preHandler
:进入请求方法之前执行;
postHandler
:请求方法执行完成之后执行;
afterCompletion
:视图渲染后执行。
二、单个拦截器执行顺序
如果只配置了一个拦截器,那么执行顺序应该是这样的:
preHandle
-> dohandle
(处理请求)-> postHandle
-> render
(渲染视图)-> afterCompletion
在 preHandle 方法中,它的返回值是 boolean 类型的,它的返回值影响着请求方法,以及 postHandle 和 afterCompletion 的执行。在 preHandle 中如果返回 false,那么后续的流程将不被执行。
三、多个拦截器执行顺序
当有多个自定义拦截器时这些方法的执行顺序则是不同,如果preHandler都返回true的情况下,preHandle方法按自定义拦截器配置的正序执行,而postHandle和afterCompletion方法按自定义拦截器配置的倒序执行;
如果某个拦截器返回false,postHandle方法都不会被执行,另外只有返回true的拦截器的afterCompletion方法才会执行。
四、源码分析
一个请求打进来时,DispatcherServlet 中的 doDispatch 方法会进行拦截器的调用,如下代码注释部分
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
// 执行拦截器的全部 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
// 执行拦截器的全部 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
// 执行拦截器的全部 afterCompletion 方法
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
// 异常后,执行拦截器的全部 afterCompletion 方法
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
// 异常后,执行拦截器的全部 afterCompletion 方法
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
在mappedHandler.applyPreHandle() 方法中,通过HandlerInterceptor[] interceptors = this.getInterceptors();
依序获得registry.addInterceptor()中加入的拦截器,for循环正序执行拦截器逻辑
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
this.triggerAfterCompletion(request, response, (Exception)null);
return false;
}
}
}
return true;
}
而在mappedHandler.applyPostHandle()方法中,同样是通过HandlerInterceptor[] interceptors = this.getInterceptors(); `依序获得registry.addInterceptor()中加入的拦截器,不过在for循环中是倒序执行逻辑
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = interceptors.length - 1; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
最后看一下mappedHandler.triggerAfterCompletion() 方法,同样for循环里是倒序执行逻辑
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
HandlerInterceptor[] interceptors = this.getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for(int i = this.interceptorIndex; i >= 0; --i) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable var8) {
logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
}
}
}
}
上面的拦截器都是按照我们配置中的顺序执行,那如果我们想要自定义顺序该怎么办呢, InterceptorRegistry 类的 addInterceptor 和 getInterceptors 方法源码如下,我们可以看到addInterceptor是将拦截器加入list集合,在getInterceptors 方法中this.registrations.stream().sorted(INTERCEPTOR_ORDER_COMPARATOR)
, 拦截器list集合按照 order 升序排序,默认order为0,可以在配置中用.order(int order)
设置顺序。
public class InterceptorRegistry {
private final List<InterceptorRegistration> registrations = new ArrayList();
private static final Comparator<Object> INTERCEPTOR_ORDER_COMPARATOR;
public InterceptorRegistry() {
}
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
this.registrations.add(registration);
return registration;
}
public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) {
WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
InterceptorRegistration registration = new InterceptorRegistration(adapted);
this.registrations.add(registration);
return registration;
}
protected List<Object> getInterceptors() {
return (List)this.registrations.stream().sorted(INTERCEPTOR_ORDER_COMPARATOR).map(InterceptorRegistration::getInterceptor).collect(Collectors.toList());
}
static {
INTERCEPTOR_ORDER_COMPARATOR = OrderComparator.INSTANCE.withSourceProvider((object) -> {
if (object instanceof InterceptorRegistration) {
InterceptorRegistration var10000 = (InterceptorRegistration)object;
((InterceptorRegistration)object).getClass();
return var10000::getOrder;
} else {
return null;
}
});
}
}
五、总结
如果不设定拦截器顺序,preHandle 方法执行顺序与拦截器注册时顺序一致,postHandle 和 afterCompletion 方法执行顺序相反;如果我们给每个拦截器设置order ,则 preHandle 方法执行顺序是按照 order 升序执行,postHandle 和 afterCompletion 方法执行顺序反之。