SpringMVC-拦截器

概述

Java 里的拦截器是动态拦截 action 调用的对象,可以对 Controller 中的方法执行之前与执行之后, 及页面显示完毕后, 执行指定的方法,自定义的拦截器必须实现 HandlerInterceptor 接口

方法介绍

preHandle

🛩在业务处理器处理请求之前被调用

postHandle

🚕在业务处理器处理完请求后被调用

afterCompletion

🏍在 DispatcherServlet 完全处理完请求后被调用

使用 SpringMVC 拦截器

拦截所有请求

创建一个类实现 HandlerInterceptor 接口详细内容如下

/**
 * @author BNTang
 */
public class MyFirstInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("处理器方法执行之前调用 → preHandle");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("处理器方法执行之后调用 → postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("页面显示完毕之后调用 → afterCompletion");
    }
}

preHandle 返回值 true 代表放行 false 代表不放行就执行不了处理器方法

然后紧接着就是修改核心配置文件了,在配置文件当中添加 拦截器

<mvc:interceptors>
    <!--设置自定义,拦截器,拦截所有请求-->
    <bean class="top.it6666.web.interceptor.MyFirstInterceptor"/>
</mvc:interceptors>

启动工程,访问工程中的某一个 Controller 查看效果如下

拦截指定请求

修改 SpringMVC 核心配置文件,配置一下需要拦截的指定请求,哪些请求不需要拦截

<mvc:interceptors>
    <mvc:interceptor>
        <!--设置拦截哪些请求-->
        <mvc:mapping path="/local"/>
        <!--设置哪些请求不拦截-->
        <mvc:exclude-mapping path="/exception"/>
        <bean class="top.it6666.web.interceptor.MyFirstInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

启动工程,访问被拦截的接口效果如下

配置多个拦截器的执行顺序

在配置了多个拦截器它们的执行顺序是怎样的呢,首先先把 preHandle 方法的返回值都改为 tru 也就是放行,然后启动工程访问 local 接口,查看控制台的输出信息如下

结果发现,preHandle 是按顺序执行了,而其他的都是按照倒序执行的,至于为什么就要来看看源码了,源码分析如下, 多个拦截器都返回 true 的源码执行流程如下,首先来看一下 preHandlepostHandleafterCompletion 这三个方法的分别调用时机吧,还是一样的从 DispatcherServlet 开始,调用时机如下图

调用时机看完了之后,现在就一个一个来分析它内部的执行流程吧,先来看 applyPreHandle 先不看别的就看循环它是怎么循环的即可,该方法的循环为 ++,那么就说明了是按照顺序一个一个取出进行执行了

经过如上的图就可以得出 preHandle 为啥是按顺序执行的了,那么紧接着就来看 postHandle 为啥是倒序执行吧,postHandle 对应的源码方法为 applyPostHandle 进入代码内容发现该方法的循环为 那么这也就是为啥是倒序执行的原因了

废话不多说,最后一个直接上源码了,原理同上

如上都是返回 true 的情况,那么返回 false 的情况呢,如下,第一个拦截器返回 false 第二个拦截器返回 true 的执行流程如下

首先调用 applyPreHandle 的时候里面有四个拦截器其中有一个是 SpringMVC 弄的,另外的3个是我们自己弄的,当循环走到我们的倒数第二个拦截器的时候你会发现,它进入到了 triggerAfterCompletion 方法内部,那么为啥呢,就因为你在 preHandle 方法中返回了一个 false 然后非一下就成了 true 然后就条件成立进入了

那么 triggerAfterCompletion 方法内部主要做了什么呢,在进入 triggerAfterCompletion 方法之前 interceptorIndex 的索引角标为 1

而 i 却是等于了 2 进入 triggerAfterCompletion 方法内部,查看详细内容如下,一样的是取出所有的拦截器数组

不过这个循环你需要注意一下了,它进入这个方法的时候 interceptorIndex 是为 1 那么我们的拦截器已经不会再从拦截器数组中获取了这也就是为什么只是输出了一个 preHandle 的原因了

这个方法执行完毕之后在往回执行直接返回了一个 false 在往上又进行了非的逻辑运算符又成了 true 然后就直接结束了后面的都不会再执行了

如上是第一个拦截器返回 false 第二个拦截器返回 true 的情况的执行流程,那么第一个拦截器返回 true 第二个拦截器返回 false 的执行流程是怎样的呢,自行修改 true false, 我这里直接讲解源码流程

如上图的解释就是我们自定义的拦截器第一个返回的是 true 那么 preHandle 执行了,preHandle 返回的是 true 这个时候不会进入 triggerAfterCompletion 然后继续往下取,取角标为 3 的拦截器这个时候 preHandle 执行了打印了我们的内容,而这个时候 preHandle 返回的是 false 非一下成为了 true 会进入 triggerAfterCompletion 方法体中,这个时候你需要注意一个变量那么就是 interceptorIndex 这个值,在最后一个拦截器进入到 triggerAfterCompletion 方法体的时候 interceptorIndex 这个值为 22,那么这个时候又去拦截器数组倒序取,那么最后一个拦截器是不会取出的,只取了第一个,那么第一个的 afterCompletion 执行了也就是会打印我们在 afterCompletion 方法体中编写的内容

执行完毕返回 false 最外面的方法运用了非的逻辑运算符就成了 true 条件成立导致后面的就都不会在执行了

内部源码分析

还是一样的套路先从 DispatcherServlet 进入,查看 doDispatch

如上方框框出来的内容是代表,要应用拦截器,点击方法进入进去查看,进入之后的代码如下

如上的内容你就关注两个点,我方框框着的点即可,如果返回 false 到了之前的那个方法,非一下就成了 true 下面的内容就不在执行了

而返回 true 就不一样了,返回 true 下面的内容就还会继续执行

posted @ 2021-02-03 14:37  BNTang  阅读(189)  评论(0编辑  收藏  举报