Filter与Interceptor深度解析:分清这两个“拦截器”,面试不再掉坑

在Java Web开发和Spring框架中,Filter(过滤器)和Interceptor(拦截器)是两个高频出现的组件------它们都能实现"请求拦截"功能,比如登录校验、日志记录、权限控制等,因此很多新手会把二者混淆。

但实际上,Filter和Interceptor在底层原理、适用范围、执行时机等方面有着本质区别。今天这篇文章,咱们就从"是什么""怎么用""有啥不同"三个层面,把这两个组件彻底讲透,帮你建立清晰的认知,下次开发和面试都能游刃有余。

一、先搞懂:Filter与Interceptor的核心定位

在正式拆解前,我们先明确一个核心结论:Filter是Java EE规范的组件,属于"Servlet容器级"的拦截;Interceptor是Spring框架的组件,属于"Spring上下文级"的拦截

简单来说,Filter不依赖于Spring,只要是Java Web项目(哪怕不用Spring)都能使用;而Interceptor是Spring的"专属工具",必须在Spring环境中才能工作,并且能深度结合Spring的IOC容器、AOP等特性。

举个生活化的例子:如果把HTTP请求比作"快递",那么Servlet容器就是"小区快递站",Spring上下文就是"你家单元楼"。Filter是快递站的"安检员",所有进入快递站的快递(不管是不是送到你家的)都要经过它检查;Interceptor是单元楼的"门禁管理员",只负责检查送到本单元楼的快递,而且还能知道快递是送给哪一户的(对应Spring的Bean信息)。

二、Servlet容器的"安检员":Filter过滤器

2.1 核心原理:基于Servlet规范的请求拦截

Filter是Java EE定义在javax.servlet包下的接口,其核心作用是在HTTP请求到达Servlet(或JSP)之前,以及响应返回给客户端之前,对请求和响应进行预处理和后处理。

Filter的工作流程可以概括为:

  1. 客户端发送HTTP请求,请求先到达Servlet容器(如Tomcat);

  2. Servlet容器根据web.xml或注解配置,找到匹配该请求的Filter;

  3. 执行Filter的doFilter()方法,在该方法中可以对请求进行预处理(如修改请求头、校验登录状态);

  4. 如果预处理通过,通过FilterChain.doFilter()将请求传递给下一个Filter或目标Servlet;

  5. Servlet处理完请求后,会返回响应,此时会再次回到Filter的doFilter()方法,进行响应的后处理(如修改响应内容、添加响应头);

  6. 最终将处理后的响应返回给客户端。

需要注意的是,Filter是"链式执行"的,如果配置了多个Filter,会按照配置顺序依次执行(一般是按照按照过滤器类名(字符串)的自然排序的顺序),形成一个过滤链。

2.2 实战:手写一个登录校验Filter

光说原理不够直观,咱们通过一个常见场景------"登录校验"来手写Filter,看看它具体怎么用。

步骤1:创建Filter实现类

实现javax.servlet.Filter接口,重写init()(初始化)、doFilter()(核心拦截逻辑)、destroy()(销毁)方法。其中doFilter()是核心。

java 复制代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

// 注解配置:拦截所有请求(/*)
@WebFilter("/*")
public class LoginCheckFilter implements Filter {

    // 初始化方法,Filter创建时执行(仅一次)
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("LoginCheckFilter初始化...");
    }

    // 核心拦截方法,每次请求匹配时执行
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 1. 转换请求响应对象(因为ServletRequest是顶层接口,需要转成HTTP专属的实现类)
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 2. 获取请求路径
        String requestURI = request.getRequestURI();

        // 3. 排除白名单(登录、注册接口不需要拦截)
        if (requestURI.contains("/login") || requestURI.contains("/register")) {
            // 直接放行
            filterChain.doFilter(request, response);
            return;
        }

        // 4. 校验登录状态:从Session中获取用户信息
        Object user = request.getSession().getAttribute("user");
        if (user != null) {
            // 已登录,放行
            filterChain.doFilter(request, response);
            return;
        }

        // 5. 未登录,返回错误响应
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write("{\"code\":401,\"msg\":\"请先登录!\"}");
    }

    // 销毁方法,Filter销毁时执行(仅一次,如服务器关闭)
    @Override
    public void destroy() {
        System.out.println("LoginCheckFilter销毁...");
    }
}
步骤2:开启Filter扫描

在Spring Boot启动类上添加@ServletComponentScan注解,让Spring扫描到我们用@WebFilter注解配置的Filter。

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan // 扫描Servlet相关组件(Filter、Servlet、Listener)
public class FilterInterceptorDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(FilterInterceptorDemoApplication.class, args);
    }
}
步骤3:测试效果
  • 访问/login:直接放行,正常返回登录页面;

  • 访问/user/info(需要登录的接口):未登录时返回{"code":401,"msg":"请先登录!"},登录后正常返回用户信息。

2.3 Filter的核心特点

  • 依赖Servlet容器:必须在Tomcat等Servlet容器中运行,脱离容器无法工作;

  • 拦截范围广:可以拦截所有HTTP请求,包括静态资源(如CSS、JS、图片)和动态请求(如Servlet、Controller);

  • 基于请求路径匹配:通过请求URI进行匹配,无法精确到Java方法级别;

  • 可操作请求和响应对象:可以修改请求头、请求参数,也可以修改响应内容、响应头;

  • 不依赖Spring:即使不用Spring,纯Servlet项目也能使用。

三、Spring的"门禁管理员":Interceptor拦截器

3.1 核心原理:基于Spring AOP的方法拦截

Interceptor是Spring框架定义在org.springframework.web.servlet包下的接口,其核心作用是在Spring MVC的Controller方法执行前后,以及视图渲染前后,对请求进行拦截和处理。

和Filter不同,Interceptor是基于Spring AOP实现的,它依赖于Spring的IOC容器,能够获取到Spring管理的Bean,因此可以实现更灵活的业务逻辑(如调用Service层方法进行权限校验)。

Interceptor的工作流程如下:

  1. 客户端发送请求,经过Filter过滤后,到达Spring MVC的DispatcherServlet(前端控制器);

  2. DispatcherServlet根据请求路径找到对应的Handler(即Controller方法);

  3. 执行该Handler对应的Interceptor的preHandle()方法(Controller方法执行前);

  4. 如果preHandle()返回true,执行目标Controller方法;如果返回false,拦截请求,不再向下执行;

  5. Controller方法执行完成后,执行Interceptor的postHandle()方法(视图渲染前);

  6. 整个请求处理完成后(视图渲染完成),执行Interceptor的afterCompletion()方法(用于资源清理等)。

3.2 实战:手写一个权限校验Interceptor

我们还是以"权限校验"为场景,手写一个Interceptor------只有拥有"ADMIN"角色的用户才能访问管理员接口。

步骤1:创建Interceptor实现类

实现HandlerInterceptor接口,重写三个核心方法:preHandle()postHandle()afterCompletion()

java 复制代码
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component // 交给Spring管理
public class AdminPermissionInterceptor implements HandlerInterceptor {

    /**
     * Controller方法执行前执行
     * @return true:放行;false:拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("AdminPermissionInterceptor:preHandle(Controller方法执行前)");
        
        // 1. 从Session获取用户角色
        String role = (String) request.getSession().getAttribute("role");
        
        // 2. 校验角色(仅ADMIN可访问)
        if ("ADMIN".equals(role)) {
            return true; // 权限通过,放行
        }
        
        // 3. 权限不足,返回错误响应
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write("{\"code\":403,\"msg\":\"权限不足,仅管理员可访问!\"}");
        return false;
    }

    /**
     * Controller方法执行后,视图渲染前执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("AdminPermissionInterceptor:postHandle(视图渲染前)");
        // 可在这里修改视图数据,如给modelAndView添加公共参数
    }

    /**
     * 整个请求处理完成后执行(视图渲染完成)
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("AdminPermissionInterceptor:afterCompletion(请求处理完成)");
        // 可在这里进行资源清理,如关闭流、释放连接等
    }
}
步骤2:配置Interceptor

通过WebMvcConfigurer接口的addInterceptors()方法,配置Interceptor的拦截路径和排除路径。

java 复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

@Configuration // 标识为配置类
public class WebMvcConfig implements WebMvcConfigurer {

    @Resource // 注入自定义的Interceptor
    private AdminPermissionInterceptor adminPermissionInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(adminPermissionInterceptor)
                .addPathPatterns("/admin/**") // 拦截/admin开头的所有请求
                .excludePathPatterns("/admin/login"); // 排除/admin/login接口(管理员登录不需要权限校验)
    }
}
步骤3:测试效果
  • 角色为ADMIN的用户访问/admin/user/list:正常返回用户列表;

  • 角色为USER的用户访问/admin/user/list:返回{"code":403,"msg":"权限不足,仅管理员可访问!"}

  • 访问/admin/login:被排除拦截,正常返回登录页面。

3.3 Interceptor的核心特点

  • 依赖Spring环境:必须在Spring(或Spring Boot)项目中使用,由Spring IOC容器管理;

  • 拦截范围精准:主要拦截Spring MVC的Controller方法,不拦截静态资源(除非特殊配置),可通过注解精准到方法级别;

  • 可获取Spring Bean:能直接注入Service、Mapper等Bean,实现复杂业务逻辑;

  • 多阶段拦截:提供preHandle、postHandle、afterCompletion三个方法,覆盖请求处理的全流程;

  • 基于Handler匹配:可以根据Controller的方法、注解等进行匹配,比Filter的路径匹配更灵活。

在拦截器中除了可以设置/**拦截所有资源外,还有一些常见拦截路径设置:

四、灵魂对比:Filter与Interceptor的8大核心差异

很多面试都会问"Filter和Interceptor有什么区别",这里我们用一张表把核心差异总结清楚,方便大家记忆:

五:什么时候用Filter?什么时候用Interceptor?

技术没有绝对的好坏,只有适合与否。结合二者的特点,我们给出明确的选型建议:

优先用Filter的场景

  1. 全局请求过滤:如统一设置请求编码(防止乱码)、拦截所有请求进行日志记录;

  2. 静态资源处理:如对CSS、JS、图片等静态资源进行压缩、缓存处理;

  3. 跨域请求处理:实现CORS(跨域资源共享)配置,允许跨域请求;

  4. 脱离Spring的场景:纯Servlet项目,或需要在Spring初始化前执行的逻辑。

优先用Interceptor的场景

  1. Spring生态内的业务拦截:如结合Spring Security进行权限校验、基于用户角色的接口拦截;

  2. Controller方法级别的拦截 :如只拦截带有@RequiresLogin注解的方法;

  3. 需要调用Spring Bean的场景:如拦截时需要调用Service层方法查询用户权限、操作数据库;

  4. 请求处理全流程干预:如在postHandle中修改视图数据,在afterCompletion中清理资源。

特殊场景:二者结合使用

在实际开发中,Filter和Interceptor往往是配合使用的。比如:

  • Filter:负责全局的编码设置、跨域处理、登录状态初步校验;

  • Interceptor:负责具体的业务权限校验(如管理员角色校验)、Controller方法日志记录。

相关推荐
带刺的坐椅1 小时前
Solon AI 开发学习6 - chat - 两种 http 流式输入输出
java·ai·solon
客梦1 小时前
Java 道路信息系统
java·笔记
k***1952 小时前
Tomcat的升级
java·tomcat
j***49563 小时前
Windows操作系统部署Tomcat详细讲解
java·windows·tomcat
草莓熊Lotso3 小时前
unordered_map/unordered_set 使用指南:差异、性能与场景选择
java·开发语言·c++·人工智能·经验分享·python·网络协议
20岁30年经验的码农5 小时前
Spring Cloud Gateway 网关技术文档
java
likuolei6 小时前
XML DOM 节点类型
xml·java·服务器
WYiQIU8 小时前
11月面了7.8家前端岗,兄弟们12月我先躺为敬...
前端·vue.js·react.js·面试·前端框架·飞书