springmvc的关于拦截器的讨论

    科技2023-12-30  94

    1:接口定义

    springMVC的拦截器对应的接口是org.springframework.web.servlet.HandlerInterceptor,接口定义如下:

    public interface HandlerInterceptor { // <1> default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } // <2> default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } // <3> default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }

    <1>方法preHandle(req, res, handler)是在调用目标handler之前调用,<2>方法postHandle(req, res, handler)是在调用目标方法成功之后调用,<3>方法afterCompletion(req, res, handler)是在请求执行完毕之后调用(不管是执行成功还是执行失败),可参考在org.springframework.web.servlet.DispatcherServlet#doDispatch调用过程,如下部分涉及拦截器调用源码(注意:拦截器是封装在HandlerExecutionChain中被调用的):

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { try { try { // 1:执行目标handler前调用拦截器的preHandle(req, res, handler) if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 2:执行目标handler mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 3: 执行目标handler成功后,执行拦截器的postHanlde(req, res, handler) mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { } catch (Throwable err) { } // <branch-1> processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { // 4.1:执行失败,执行拦截器的afterCompletion(req, res, handler)方法 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { // 4.2:执行失败,执行拦截器的afterCompletion(req, res, handler)方法 triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } }

    另外这里没有请求成功结束后的afterCompletion(req, res, handler)方法的调用,其调用是在<branch-1>方法中,调用源码如下:

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { // 5:请求处理成功,调用afterCompletion(req, res, handler) if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }

    既然HandlerInterceptor的调用是通过org.springframework.web.servlet.HandlerExecutionChain处理器执行链来调用的,那就来看下这个类。

    2:HandlerExecutionChain

    2.1:构造方法

    一共两个构造函数,一个指定handler,一个指定了handler和拦截器。

    public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[]) null); } public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); this.interceptorList = new ArrayList<>(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); } else { this.handler = handler; this.interceptors = interceptors; } }

    在org.springframework.web.servlet.handler.AbstractHandlerMapping中使用的是只有hander的构造函数,调用源码如下:

    org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); }

    2.2:主要变量

    private final Object handler; @Nullable private HandlerInterceptor[] interceptors; @Nullable private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1;

    Object handler存储目标handler,interceptors,interceptorList都是用来存储拦截器的,代码逻辑使用的是interceptorList,interceptors可以认为只是过度使用,interceptorIndex记录已经执行的位置,使用如下:

    org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { ... if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { ... this.interceptorIndex = i; } } return true; }

    2.3:主要方法

    addInterceptor 该方法有两个版本: public void addInterceptor(HandlerInterceptor interceptor) {} public void addInterceptors(HandlerInterceptor... interceptors) {}

    在org.springframework.web.servlet.handler.AbstractHandlerMapping中使用的是第一个方法。源码:

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { ... for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { ... if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { ... } } return chain; } getInterceptors 获取拦截器数组,源码: public HandlerInterceptor[] getInterceptors() { if (this.interceptors == null && this.interceptorList != null) { this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]); } return this.interceptors; } 调用目标拦截器 三个方法,applyPreHanlder(req, res),applyPostHandler,triggerAfterCompletion,源码如下: org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } org.springframework.web.servlet.HandlerExecutionChain#applyPostHandle 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); } } } org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion 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); } } } }

    3:MappedInterceptor

    org.springframework.web.servlet.handler.MappedInterceptor是org.springframe,web.servlet.HandlerInterceptor的子类,类签名:

    public final class MappedInterceptor implements HandlerInterceptor {}

    通过uml表示: 我们使用<mvc:interceptors>标签配置的拦截器信息就会被解析为MappedInterceptor对象,如下定义:

    <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/testinterceptor/hi"/> <bean class="dongshi.handlerinterceptor.DemoHandlerInterceptor"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/testinterceptor/hi"/> <bean class="dongshi.handlerinterceptor.DemoHandlerInterceptor1"/> </mvc:interceptor> </mvc:interceptors>

    debugorg.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext#adaptedInterceptors可以看到,如下:

    3.1:路径匹配方法match

    源码:

    public boolean matches(String lookupPath, PathMatcher pathMatcher) { PathMatcher pathMatcherToUse = (this.pathMatcher != null ? this.pathMatcher : pathMatcher); // <1> if (!ObjectUtils.isEmpty(this.excludePatterns)) { for (String pattern : this.excludePatterns) { if (pathMatcherToUse.match(pattern, lookupPath)) { return false; } } } // <2> if (ObjectUtils.isEmpty(this.includePatterns)) { return true; } // <3> for (String pattern : this.includePatterns) { if (pathMatcherToUse.match(pattern, lookupPath)) { return true; } } return false; }

    <1>处代码如果通过排除路径集合,过滤,满足排除路径某个则不匹配,<2>处代码如果是包含路径为空则认为拦截所有,即匹配。<3>通过包含路径集合查看是否匹配,匹配其中一个则认为匹配。到最后说明不匹配,直接返回false。该方法的调用源码如下:

    org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { ... for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } ... } return chain; }

    最后:都让开,我要喝瑞幸

    Processed: 0.012, SQL: 8