HandlerInterceptor拦截器的原理

简介: HandlerInterceptor拦截器的原理

是什么

HandlerInterceptor拦截的是请求,是springMVC项目中的拦截器,它拦截的目标是请求的地址。也就是说,它可以对请求进行拦截处理,所有实现了HandlerInterceptor,并且进行了配置的的类,都有这个能力,它的原理,和Filter很相似,我们一起来看一下具体代码是怎么回事。

来个例子

首先我们自己建一个springboot的项目,然后写两个测试接口:

@RequestMapping()
@Controller
@ResponseBody
public class TestController {
    @GetMapping("/test")
    public void test(){
        System.out.println("test");
    }
    @GetMapping("/login/test")
    public void login(){
        TestController.class.getClassLoader();
        System.out.println("login test");
    }

然后再写两个拦截器:

public class UserIntercepter implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler)
            throws Exception {
        System.out.println("MyInterceptor 拦截器执行preHandle()方法");
        return true;
    }
    // 当preHandle方法返回值为true的时候才会执行。
    // 重写postHandle方法,在请求完成后执行。
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle执行了");
    }
    // 当preHandle方法返回值为true的时候才会执行。
    // 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion执行了");
    }
}

第二个:

public class LoginIntercepter implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler)
            throws Exception {
        System.out.println("LoginIntercepter 拦截器执行preHandle()方法");
        return true;
    }
    // 当preHandle方法返回值为true的时候才会执行。
    // 重写postHandle方法,在请求完成后执行。
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("LoginIntercepter的postHandle执行了");
    }
    // 当preHandle方法返回值为true的时候才会执行。
    // 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("LoginIntercepter的afterCompletion执行了");
    }
}

拦截器写好了,还需要写一个配置类把拦截器配置上才可以起效

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserIntercepter())
                .addPathPatterns("/**") ;  //拦截所有的路径
        registry.addInterceptor(new LoginIntercepter())
                .addPathPatterns("/login/**");
    }
}

什么时候加载的

一般来说,我们的类想要被spring容器管理,需要给类加上@Service,@Componet之类的注解,但是很明显,我们的两个拦截器是没有加的,但是我们的配置类加了,所以我们给配置类打个断点,然后启动项目,看看发生了什么。

断点停下来之后,往上找,看看是哪里在调用:

注意这是倒着网上找的,所以,很明显,在程序启动的时候,我们自己写的拦截器就被spring的容器管理起来了。

什么时候起效的

那么这玩意儿咋起效呢?这就得看一下我们的org.springframework.web.servlet.DispatcherServlet中的doDispatch(HttpServletRequest request, HttpServletResponse response)方法。

调用接口-找到拦截器

首先我们调用一下test接口,然后看一下org.springframework.web.servlet.DispatcherServlet中的doDispatch(HttpServletRequest request, HttpServletResponse response)断点,可以看到,走到这一步的时候,其实拦截器已经被找到了,我们有两个拦截器,这里加载了全部拦截的那一个。

然后我们进入getHandler(HttpServletRequest request)看看是怎么找到这个拦截器的。

可以看到,拦截器都保存在这个handlerMappings中的RequestMappingHandlerMapping中,然后mapping.getHandler(request)就负责找到接口对应的servlet和interceptors。

这个handlerMappings会在有第一次接口调用的时候被初始化,代码在这里:

看一下具体是怎么拿的:

注意一下,这里并不需要从头初始化,知识根据类型,从ApplicationContext,也就是容器里请求拿出来就可以。

调用接口-拦截器起效

现在我们已经有了对应的servlet和interceptors,那它如何起效呢,先来整体看一下:

依次执行各个拦截器的preHandle

其他的也大致相同。

总结

大致流程总结一下就是,我们编写的拦截器,会通过我们的配置类,被spring的容器管理起来,也就是程序启动时就被加载到容器中,然后当我们需要使用的时候,DispatchServlet初始化的时候,拦截器会被加载到它的属性private List<HandlerMapping> handlerMappings;中,注意,这是个list,我们的接口和拦截器都只属于其中的一个,就是RequestMappingHandlerMapping这个属性,找到对应的处理器之后,就按照流程执行了

以上,其实就HandlerInterceptor

参考

DispatcherServlet浅析

相关文章
|
4月前
|
人工智能 应用服务中间件 网络安全
2026年阿里云部署OpenClaw(Clawdbot)流程,OpenClaw无缝接入个人微信攻略
在AI智能助手深度融入日常沟通的2026年,OpenClaw(曾用名Clawdbot、Moltbot)作为功能强大的开源AI框架,支持邮件管理、代码生成、信息查询等多元化任务。将其接入个人微信,能实现“随时随地发指令、AI助手秒响应”的便捷体验——无需打开专用客户端,通过微信即可调用OpenClaw的全部功能,无论是查询资讯、生成文档还是执行自动化任务,都能高效完成。
7948 1
|
Dart 编译器 API
Dart笔记:Dart 库
Dart笔记:Dart 库
455 0
|
人工智能 物联网 开发工具
本地搭建 Stable Diffusion,还有完整的安装包
本地搭建 Stable Diffusion,还有完整的安装包
824 0
|
5月前
|
人工智能 运维 前端开发
Claude Code 30k+ star官方插件,小白也能写专业级代码
Superpowers是Claude Code官方插件,由核心开发者Jesse打造,上线3个月获3万star。它集成brainstorming、TDD、系统化调试等专业开发流程,让AI写代码更规范高效。开源免费,安装简单,实测显著提升开发质量与效率,值得开发者尝试。
12874 5
|
11月前
|
XML 人工智能 监控
SpringBoot实战:七种统计方法耗时的实现方式
在Spring Boot开发中,统计方法执行时间是性能优化的重要手段。本文介绍了七种实现方法耗时统计的技巧,包括手动使用StopWatch、AOP全局监控、自定义注解+切面、拦截器、Filter、Actuator+Micrometer集成以及事件监听等方式。每种方法适用于不同场景,开发者可根据需求选择合适的方案,从而更高效地定位性能瓶颈并提升系统响应速度。
1344 5
|
11月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
Java Spring
OpenFeign 如何设置动态 URL?
本文介绍如何在OpenFeign中设置动态 URL
OpenFeign 如何设置动态 URL?