摘要:在 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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("进入拦截器preHandle");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("进入拦截器postHandle");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("进入拦截器afterCompletion");}}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {// 初始化操作}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("进入过滤器");filterChain.doFilter(servletRequest, servletResponse);System.out.println("离开过滤器");}@Overridepublic 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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("进入拦截器preHandle");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("进入拦截器postHandle");}@Overridepublic 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;@Configurationpublic class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor).addPathPatterns("/*");}}当我们发起一个请求时,控制台的输出顺序会是:“进入过滤器” -> “进入拦截器 preHandle” -> 控制器方法执行 -> “进入拦截器 postHandle” -> “进入拦截器 afterCompletion” -> “离开过滤器”,这就像一份清晰的 “请求处理流程说明书”,展示了请求先经过过滤器,再经过拦截器的流程。
所以,下次再遇到关于过滤器和拦截器执行顺序的问题,你就可以自信满满地解答啦!如果你在实际开发中还有其他关于 Spring Boot 的疑问,欢迎在评论区留言分享,大家一起探讨学习。也别忘了点赞、收藏这篇文章,方便随时回顾,让我们一起在后端开发的道路上不断进步!
来源:从程序员到架构师一点号