Spring 拦截器流程及多个拦截器的顺序

简介: Spring 拦截器流程及多个拦截器的顺序

      拦截器是 Spring MVC 中的组件,它可以在进入请求方法前做一些操作,也可以在请求方法后和渲染视图后做一些事情。

拦截器的定义

      SpringMVC 的拦截器只需要实现 HandlerInterceptor 接口,并进行配置即可。HandlerInterceptor 接口的定义如下:

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

      在 HandlerInterceptor 中共有三个方法,每个方法的含义如下:

preHandler:进入请求方法之前执行;

postHandler:请求方法执行完成之后执行;

afterCompletion:视图渲染后执行。

拦截器的执行流程

       在 preHandle 方法中,它的返回值是 boolean 类型的,它的返回值影响着请求方法,以及 postHandle 和 afterCompletion 的执行。具体如下。


       也就是说,在 preHandle 中如果返回 false,那么后续的流程将不被执行,这可能也是拦截器命名的由来。

测试拦截器

      写一个简单拦截器,代码如下:

@Slf4j
public class TestInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandler");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandler");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}

       创建了一个 TestInterceptor 的监听器类,它实现了 HandlerInterceptor 的所有接口。写完 TestInterceptor 还需要进行注册。代码如下:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(testInterceptor());
    }


    再来写一个简单的请求方法,代码如下:

@GetMapping("test")
public String test()
{
    return "test";
}

      来启动我们的项目,并进行访问,控制台的输出如下:

2021-05-05 16:02:08.110  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:02:08.111  INFO 88509 --- [nio-8081-exec-6] com.example.demo.TestInterceptor         : afterCompletion

多个拦截器的执行顺序

       我们来写多个相同的监听器,分别是 TestInterceptor、TestInterceptor2 和 TestInterceptor3。然后我们进行注册,注册代码如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor3());
}

       请求我们的方法,输出如下:

2021-05-05 16:09:57.735  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:09:57.736  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : preHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : postHandler3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : postHandler2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : postHandler
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor3        : afterCompletion3
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : afterCompletion2
2021-05-05 16:09:57.755  INFO 88572 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

       注意观察输出的顺序,preHandle 方法是按注册顺序进行执行的,而 postHandle 和 afterCompletion 跟注册顺序是相反的。

让 preHandle 进行拦截

     我们让 TestInterceptor2 的 preHandle 返回值为 false,然后查看一下输出内容。

2021-05-05 16:14:00.997  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : preHandler
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2
2021-05-05 16:14:00.998  INFO 88582 --- [nio-8081-exec-1] com.example.demo.TestInterceptor         : afterCompletion

       可以看到,TestInterceptor2 的 preHandle 的返回值为 false 以后,相当于在 TestInterceptor2 的 preHandle 后续流程则不再继续执行了。

       我们调整一下注册的顺序,代码如下:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(testInterceptor2());
    registry.addInterceptor(testInterceptor());
    registry.addInterceptor(testInterceptor3());
}

      修改顺序后的输出如下:

2021-05-05 16:17:23.956  INFO 88589 --- [nio-8081-exec-1] com.example.demo.TestInterceptor2        : preHandler2

   可以看到它后面的流程都被拦截了,没有机会执行了。

总结

      拦截器是使用一个 List 进行保存,我们可以在项目中添加多个拦截器来完成不同的功能,比如可以进行 Token 的验证,权限的获取等。我们可以放到不同的拦截器中来进行相关的操作。

相关文章
|
2月前
|
XML 前端开发 Java
深入了解Spring MVC工作流程
深入了解Spring MVC工作流程
|
4月前
|
Java Spring
Spring 源码阅读 72:基于 CGLIB 的 AOP 代理的原理(2)- 拦截器的查找与执行
【1月更文挑战第7天】本文分析了基于 CGLIB 的 AOP 代理如何查找和执行拦截器链,其主要的逻辑在 DynamicAdvisedInterceptor 的intercept方法执行。
35 1
|
4月前
|
缓存 Java Spring
Spring 源码阅读 66:基于 JDK 的 AOP 代理如何获取拦截器链(4)- 将 Advice 封装为拦截器
【1月更文挑战第1天】本文分析了 Advice 被封装成 MethodInterceptor 的过程,Spring AOP 用到的五种 Advice 中,有些本身就是 MethodInterceptor 的实现类,而有些需要通过适配器的封装。
44 0
|
8天前
|
前端开发 Java Spring
[AIGC] Spring Interceptor 拦截器详解
[AIGC] Spring Interceptor 拦截器详解
|
2月前
|
JSON Java 数据库连接
【spring(五)】SpringMvc总结 SSM整合流程
【spring(五)】SpringMvc总结 SSM整合流程
|
2月前
|
缓存 前端开发 Java
【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法
【Spring底层原理高级进阶】轻松掌握 Spring MVC 的拦截器机制:深入理解 HandlerInterceptor 接口和其实现类的用法
|
3月前
spring-state-machine拦截器
spring-state-machine拦截器
24 0
|
3月前
|
缓存 Java uml
SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
SpringBoot2 | Spring IOC 流程中核心扩展接口的12个扩展点源码分析(十一)
41 0
|
4月前
|
Java Spring
spring的两种拦截器HandlerInterceptor和MethodInterceptor
spring的两种拦截器HandlerInterceptor和MethodInterceptor
33 0
|
4月前
|
前端开发 Java 应用服务中间件
掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!
掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!