Spring Boot 中请求到底先进入过滤器还是拦截器?
在 Spring Boot 开发的日常中,你是否遇到过这样的情况:在过滤器和拦截器里精心编写了日志打印代码,可运行后输出顺序却让人摸不着头脑,不禁疑惑,请求到底是先进入过滤器,还是先进入拦截器呢?相信不少在互联网大厂从事后端开发的小伙伴,都被这个问题困扰过。
过滤器与拦截器:功能相似却各有不同
在 Spring Boot 项目开发的 “工具箱” 中,过滤器(Filter)和拦截器(Interceptor)是两个非常重要的 “工具”,它们在请求处理过程中都起着关键作用 。但由于功能上有一定相似性,很多开发者容易混淆二者。
过滤器是 Servlet 规范的一部分,依赖于 Servlet 容器,它就像是一个 “全能门卫”,可以对几乎所有的请求进行过滤处理,比如我们常见的字符编码设置、请求参数校验等;而拦截器则是 Spring MVC 框架中的概念,基于 Java 反射机制,它更像是 Spring MVC 框架专属的 “安检员”,主要针对 Spring MVC 管理的请求进行拦截,常用于权限验证、记录请求耗时等操作。二者的工作原理和作用范围的差异,也就导致了它们在请求处理流程中执行顺序的不同。
请求处理顺序:过滤器在前,拦截器在后
其实,在 Spring Boot 这个 “请求处理工厂” 里,请求是先进入过滤器,再进入拦截器的。具体来说,当一个请求进入 Spring Boot 应用时,首先会经过 Servlet 容器中的过滤器链,过滤器可以对请求进行预处理,例如修改请求头、判断请求是否合法等操作,就像在进入工厂大门前,先经过一轮全面检查。当过滤器链执行完毕,请求才会进入到 Spring MVC 框架中,这时候拦截器才开始发挥作用,拦截器会在控制器方法执行前后进行一系列操作,比如权限检查、日志记录等,就像是进入特定车间前的二次安检。
代码示例验证执行顺序
为了让大家更清晰地理解,我们来看一个简单的代码示例。首先创建一个过滤器:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("进入拦截器preHandle");
return true;
}
@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");
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化操作
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("进入过滤器");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("离开过滤器");
}
@Override
public void destroy() {
// 销毁操作
}
}
再创建一个拦截器:
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("进入拦截器preHandle");
return true;
}
@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");
}
}
然后在配置类中注册拦截器:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/*");
}
}
当我们发起一个请求时,控制台的输出顺序会是:“进入过滤器” -> “进入拦截器 preHandle” -> 控制器方法执行 -> “进入拦截器 postHandle” -> “进入拦截器 afterCompletion” -> “离开过滤器”,这就像一份清晰的 “请求处理流程说明书”,展示了请求先经过过滤器,再经过拦截器的流程。
所以,下次再遇到关于过滤器和拦截器执行顺序的问题,你就可以自信满满地解答啦!如果你在实际开发中还有其他关于 Spring Boot 的疑问,欢迎在评论区留言分享,大家一起探讨学习。也别忘了点赞、收藏这篇文章,方便随时回顾,让我们一起在后端开发的道路上不断进步!
相关文章
- SpringBoot注解 & 拦截器 & 反射
- 如何批量获取指定歌手的音乐(批量搜索歌曲)
- 系列:第五篇—接口发生异常如何统一处理
- Spring Cloud Hystrix熔断与负载均衡深度解析:原理实践与避坑指南
- Spring WebFlux核心处理组件DispatcherHandler
- SpringCloud相关组件——健康监控!
- springboot中ServletComponentScan注解的作用
- JavaEE概述总结:Servlet生命周期+JSP内置对象
- Spring Boot3中解决跨域问题的五种常用方法?
- Java中拦截器和过滤器的比较(java 拦截器和过滤器)