HandlerInterceptor 处理器拦截器接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 // HandlerInterceptor.java public interface HandlerInterceptor { /** * 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 执行之前 */ default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } /** * 拦截处理器,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 执行成功之后 */ default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } /** * 拦截处理器,在 {@link HandlerAdapter} 执行完之后,无论成功还是失败 * * 并且,只有 {@link #preHandle(HttpServletRequest, HttpServletResponse, Object)} 执行成功之后,才会被执行 */ default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
HandlerExecutionChain 处理器执行链。
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 // HandlerExecutionChain.java /** * 处理器 */ private final Object handler; /** * 拦截器数组 */ @Nullable private HandlerInterceptor[] interceptors; /** * 拦截器数组。 * * 在实际使用时,会调用 {@link #getInterceptors()} 方法,初始化到 {@link #interceptors} 中 */ @Nullable private List<HandlerInterceptor> interceptorList; /** * 已执行 {@link HandlerInterceptor#preHandle(HttpServletRequest, HttpServletResponse, Object)} 的位置 * * 主要用于实现 {@link #applyPostHandle(HttpServletRequest, HttpServletResponse, ModelAndView)} 的逻辑 */ private int interceptorIndex = -1; /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute */ public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[]) null); } /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute * @param interceptors the array of interceptors to apply * (in the given order) before the handler itself executes */ public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); // 初始化到 interceptorList 中 this.interceptorList = new ArrayList<>(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); // 逻辑比较简单,就是将前者添加到后者中,即添加到 interceptorList 中 CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); // 逻辑比较简单,就是将前者添加到后者中,即添加到 interceptorList 中 } else { this.handler = handler; this.interceptors = interceptors; } }
addInterceptor 添加拦截器到 interceptorList 中
1 2 3 4 5 // HandlerExecutionChain.java public void addInterceptor(HandlerInterceptor interceptor) { initInterceptorList().add(interceptor); }
首先,会调用 #initInterceptorList() 方法,保证 interceptorList 已初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // HandlerExecutionChain.java private List<HandlerInterceptor> initInterceptorList() { // 如果 interceptorList 为空,则初始化为 ArrayList if (this.interceptorList == null) { this.interceptorList = new ArrayList<>(); // 如果 interceptors 非空,则添加到 interceptorList 中 if (this.interceptors != null) { // An interceptor array specified through the constructor CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList); } } // 置空 interceptors this.interceptors = null; // 返回 interceptorList return this.interceptorList; }
虽然代码有点长,但是逻辑很简单。实际上,我们将 interceptorList 是 interceptors 的配置。
addInterceptor(HandlerInterceptor interceptor) 方法,添加拦截器们到 interceptorList 中
1 2 3 4 5 6 7 // HandlerExecutionChain.java public void addInterceptors(HandlerInterceptor... interceptors) { if (!ObjectUtils.isEmpty(interceptors)) { CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList()); } }
getInterceptors 获得 interceptors 数组
1 2 3 4 5 6 7 8 9 10 11 // HandlerExecutionChain.java @Nullable public HandlerInterceptor[] getInterceptors() { // 将 interceptorList 初始化到 interceptors 中 if (this.interceptors == null && this.interceptorList != null) { this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]); } // 返回 interceptors 数组 return this.interceptors; }
applyPreHandle 应用拦截器的前置处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // HandlerExecutionChain.java /** * 应用拦截器的前置处理 * * Apply preHandle methods of registered interceptors. * @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. */ boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { // <1> 获得拦截器数组 HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { // <2> 遍历拦截器数组 for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; // <3> 前置处理 if (!interceptor.preHandle(request, response, this.handler)) { // <3.1> 触发已完成处理 triggerAfterCompletion(request, response, null); // 返回 false ,前置处理失败 return false; } // <3.2> 标记 interceptorIndex 位置 this.interceptorIndex = i; } } // <4> 返回 true ,前置处理成功 return true; }
3处,执行拦截器的前置处理。如果成功,则返回 true ,否则返回 false
3.1处,执行失败,则调用 #triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) 方法,触发已完成处理。注意,此处不是触发当前拦截器的已完成逻辑,而是触发 [0, interceptorIndex) 这几个拦截器已完成的逻辑( 不包括当前这个拦截器 ),并且是按照倒序执行的。返回 false ,因为有拦截器执行失败
3.2处,标记 interceptorIndex 位置
triggerAfterCompletion 触发拦截器的已完成处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // HandlerExecutionChain.java /** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. */ void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { // 获得拦截器数组 HandlerInterceptor[] interceptors = 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 ex2) { // 注意,如果执行失败,仅仅会打印错误日志,不会结束循环 logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } }
applyPostHandle 应用拦截器的后置处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // HandlerExecutionChain.java void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { // 获得拦截器数组 HandlerInterceptor[] interceptors = 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); } } }
HandlerInterceptor实现类
MappedInterceptor 实现 HandlerInterceptor 接口,支持地址匹配的 HandlerInterceptor 实现类。
1 2 3 4 5 6 7 <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/interceptor/**" /> <mvc:exclude-mapping path="/interceptor/b/*" /> <bean class="com.elim.learn.spring.mvc.interceptor.MyInterceptor" /> </mvc:interceptor> </mvc:interceptors>
每一个 <mvc:interceptor /> 标签,将被解析成一个 MappedInterceptor Bean 对象。
构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 // MappedInterceptor.java /** * 匹配的路径 */ @Nullable private final String[] includePatterns; /** * 不匹配的路径 */ @Nullable private final String[] excludePatterns; /** * 路径匹配器 */ @Nullable private PathMatcher pathMatcher; /** * HandlerInterceptor 拦截器对象 */ private final HandlerInterceptor interceptor; public MappedInterceptor(@Nullable String[] includePatterns, HandlerInterceptor interceptor) { this(includePatterns, null, interceptor); } public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns, HandlerInterceptor interceptor) { this.includePatterns = includePatterns; this.excludePatterns = excludePatterns; this.interceptor = interceptor; } public MappedInterceptor(@Nullable String[] includePatterns, WebRequestInterceptor interceptor) { this(includePatterns, null, interceptor); } public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns, WebRequestInterceptor interceptor) { this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor)); }
includePatterns + excludePatterns + pathMatcher 属性,匹配路径。
interceptor 拦截器
matches 判断路径是否匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 // MappedInterceptor.java /** * Determine a match for the given lookup path. * @param lookupPath the current request path * @param pathMatcher a path matcher for path pattern matching * @return {@code true} if the interceptor applies to the given request path */ public boolean matches(String lookupPath, PathMatcher pathMatcher) { PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher); // 先排重 if (!ObjectUtils.isEmpty(this.excludePatterns)) { for (String pattern : this.excludePatterns) { if (pathMatcherToUse.match(pattern, lookupPath)) { // 匹配 return false; } } } // 特殊,如果包含为空,则默认就是包含 if (ObjectUtils.isEmpty(this.includePatterns)) { return true; } // 后包含 for (String pattern : this.includePatterns) { if (pathMatcherToUse.match(pattern, lookupPath)) { // 匹配 return true; } } return false; }
拦截方法实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // MappedInterceptor.java @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return this.interceptor.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { this.interceptor.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { this.interceptor.afterCompletion(request, response, handler, ex); }
拦截器配置 在 Spring MVC 中,有多种方式,配置拦截器
<mvc:interceptors /> 标签
每一个 <mvc:interceptor /> 标签会被解析成 MappedInterceptor 对象,注册到 Spring IOC 容器中。
在 AbstractHandlerMapping 的 #detectMappedInterceptors(List mappedInterceptors) 方法中,会扫描 MappedInterceptor Bean 。
1 2 3 4 5 6 7 8 9 // AbstractHandlerMapping.java protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) { // 扫描已注册的 MappedInterceptor 的 Bean 们,添加到 mappedInterceptors 中 // MappedInterceptor 会根据请求路径做匹配,是否进行拦截。 mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( obtainApplicationContext(), MappedInterceptor.class, true, false).values()); }