SpringBoot 拦截器和过滤器的区别

SpringBoot 拦截器和过滤器的区别

SpringBoot 中的拦截器(Interceptor)和过滤器(Filter)都是用于请求处理的增强机制,但它们存在以下核心区别:

对比维度 过滤器(Filter) 拦截器(Interceptor)
所属规范 Servlet 规范( javax.servlet 包) Spring 框架( org.springframework 包)
应用范围 所有进入容器的请求(包括静态资源) 仅针对 Spring MVC 控制器的请求
触发时机 在 Servlet 容器处理请求前/后 在 Spring MVC 处理器执行前/后/完成时
实现方式 实现 javax.servlet.Filter 接口 实现 org.springframework.web.servlet.HandlerInterceptor 接口
依赖注入 不支持(Filter 由 Servlet 容器管理) 支持(Interceptor 由 Spring 容器管理)
访问上下文 仅能访问 ServletRequest 和 ServletResponse 可访问 Handler、ModelAndView 等 Spring 组件
执行顺序 基于 FilterRegistrationBean 配置的顺序 基于 InterceptorRegistry 注册的顺序

设计模式分析

过滤器(Filter)采用的设计模式
  1. 责任链模式(Chain of Responsibility)

    • 多个 Filter 形成链式调用,每个 Filter 可以决定是否继续传递请求到下一个环节

    • 示例代码体现:

      java 复制代码
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
          throws IOException, ServletException {
          // 前置处理
          chain.doFilter(request, response); // 传递到下一个过滤器或Servlet
          // 后置处理
      }
  2. 装饰器模式(Decorator)

    • 通过 Filter 包装原始请求/响应对象,增强其功能(如字符编码处理)
    • 示例:CharacterEncodingFilter 装饰请求对象以设置字符编码
拦截器(Interceptor)采用的设计模式
  1. AOP(面向切面编程)

    • 拦截器本质是 Spring AOP 的一种实现,通过对 Handler 方法的环绕通知实现增强

    • 示例:

      java 复制代码
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
          throws Exception {
          // 前置处理,返回true继续执行后续拦截器和Handler
          return true;
      }
  2. 观察者模式(Observer)

    • 拦截器的 postHandleafterCompletion 方法类似于事件监听机制
    • 当请求处理完成或发生异常时,触发相应的回调方法

典型应用场景对比

场景 过滤器(Filter) 拦截器(Interceptor)
请求编码处理 CharacterEncodingFilter -
跨域请求处理 CorsFilter -
权限校验 基于 Servlet API 的简单权限检查 基于 Spring Security 的复杂权限控制
请求日志记录 记录原始请求信息 记录完整的处理时间和结果
事务管理 - 基于 @Transactional 注解的事务拦截
性能监控 统计请求总耗时 统计 Controller 方法执行耗时

选择建议

  • 使用过滤器:需要对所有请求进行统一处理(如编码、安全头设置)
  • 使用拦截器:需要访问 Spring 容器中的 Bean 或处理 MVC 相关对象(如 ModelAndView)
  • 组合使用:复杂场景下,可结合过滤器和拦截器实现多层级处理(如:过滤器处理基础安全,拦截器处理业务权限)

下面将详细介绍Spring Boot中过滤器(Filter)和拦截器(Interceptor)的使用方法,并提供示例代码:

一、过滤器(Filter)的使用步骤

1. 创建Filter类并实现Filter接口
java 复制代码
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(urlPatterns = "/*", filterName = "requestLogFilter")
public class RequestLogFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        
        // 前置处理:记录请求信息
        System.out.println("Filter: 请求URL - " + httpRequest.getRequestURI());
        
        // 传递请求到下一个过滤器或Servlet
        chain.doFilter(request, response);
        
        // 后置处理:记录响应信息
        System.out.println("Filter: 请求处理完成");
    }
}
2. 启用Servlet组件扫描(如果未使用@ServletComponentScan)
java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan  // 启用Servlet组件扫描
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
3. 或通过Java配置注册Filter(推荐方式)
java 复制代码
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<RequestLogFilter> loggingFilter() {
        FilterRegistrationBean<RequestLogFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new RequestLogFilter());
        registrationBean.addUrlPatterns("/*");  // 拦截所有请求
        registrationBean.setOrder(1);  // 设置过滤器执行顺序
        return registrationBean;
    }
}

二、拦截器(Interceptor)的使用步骤

1. 创建Interceptor类并实现HandlerInterceptor接口
java 复制代码
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class RequestTimeInterceptor implements HandlerInterceptor {

    private ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 前置处理:记录请求开始时间
        long startTime = System.currentTimeMillis();
        startTimeThreadLocal.set(startTime);
        System.out.println("Interceptor: 请求开始 - " + request.getRequestURI());
        return true;  // 返回true继续执行后续拦截器和Handler
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) {
        // 后置处理:Controller方法执行完成后,但视图渲染前
        System.out.println("Interceptor: 请求处理中 - " + request.getRequestURI());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) {
        // 完成处理:视图渲染完成后,可用于资源清理
        long startTime = startTimeThreadLocal.get();
        long endTime = System.currentTimeMillis();
        System.out.println("Interceptor: 请求完成 - " + request.getRequestURI() 
                          + " 耗时: " + (endTime - startTime) + "ms");
        startTimeThreadLocal.remove();  // 防止内存泄漏
    }
}
2. 注册拦截器到Spring MVC
java 复制代码
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 WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestTimeInterceptor())
                .addPathPatterns("/**")  // 拦截所有请求
                .excludePathPatterns("/static/**", "/error");  // 排除静态资源和错误页面
    }
}

三、过滤器 vs 拦截器执行顺序示例

执行顺序配置
java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册第一个拦截器(order=1)
        registry.addInterceptor(new FirstInterceptor()).addPathPatterns("/**").order(1);
        // 注册第二个拦截器(order=2)
        registry.addInterceptor(new SecondInterceptor()).addPathPatterns("/**").order(2);
    }
}

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<FirstFilter> firstFilter() {
        FilterRegistrationBean<FirstFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new FirstFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(1);  // 过滤器顺序1
        return registration;
    }

    @Bean
    public FilterRegistrationBean<SecondFilter> secondFilter() {
        FilterRegistrationBean<SecondFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new SecondFilter());
        registration.addUrlPatterns("/*");
        registration.setOrder(2);  // 过滤器顺序2
        return registration;
    }
}
执行顺序结果

对于一个HTTP请求,执行顺序为:

复制代码
FirstFilter.pre -> SecondFilter.pre -> 
FirstInterceptor.pre -> SecondInterceptor.pre -> 
Controller处理请求 -> 
SecondInterceptor.post -> FirstInterceptor.post -> 
视图渲染 -> 
SecondInterceptor.after -> FirstInterceptor.after -> 
SecondFilter.post -> FirstFilter.post

四、常见应用场景代码示例

1. 权限校验拦截器
java 复制代码
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String token = request.getHeader("Authorization");
        
        if (token == null || !validateToken(token)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未授权");
            return false;
        }
        
        // 将用户信息存入Request,供后续使用
        request.setAttribute("user", parseUserFromToken(token));
        return true;
    }
    
    private boolean validateToken(String token) {
        // 验证Token逻辑
        return token.startsWith("Bearer ");
    }
    
    private User parseUserFromToken(String token) {
        // 解析用户信息
        return new User("testUser");
    }
}
2. 字符编码过滤器
java 复制代码
@WebFilter(urlPatterns = "/*", filterName = "encodingFilter")
public class EncodingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }
}

五、关键配置说明

配置项 过滤器(Filter) 拦截器(Interceptor)
拦截路径配置 @WebFilter(urlPatterns = "/*") registry.addPathPatterns("/**")
排除路径配置 不直接支持,需在doFilter中手动判断 registry.excludePathPatterns("/static/**")
执行顺序控制 通过 FilterRegistrationBean.setOrder() 通过 addInterceptor().order() 或注册顺序
依赖注入 不支持(非Spring管理) 支持(可注入Service等Bean)
获取Spring上下文 需手动获取ApplicationContext 可直接注入所需组件

六、注意事项

  1. 过滤器注意点

    • Filter由Servlet容器管理,生命周期独立于Spring
    • 无法直接注入Spring Bean,需通过ApplicationContext获取
    • 对所有请求生效,包括静态资源和错误请求
  2. 拦截器注意点

    • Interceptor由Spring管理,可使用依赖注入
    • 仅拦截Spring MVC处理的请求,对静态资源无效
    • 可访问HandlerMethod、ModelAndView等Spring MVC特有对象
  3. 性能考虑

    • 过滤器执行更早,性能开销更小
    • 拦截器功能更强大,但依赖Spring MVC上下文

根据实际需求合理选择过滤器或拦截器,复杂场景可组合使用两者。

相关推荐
倒流时光三十年22 分钟前
SpringBoot 数据库同步 Elasticsearch 性能优化
数据库·spring boot·elasticsearch
码农小卡拉1 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot
Dragon Wu1 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
一个有梦有戏的人1 小时前
Python3基础:进阶基础,筑牢编程底层能力
后端·python
爬山算法2 小时前
Hibernate(88)如何在负载测试中使用Hibernate?
java·后端·hibernate
独断万古他化2 小时前
【Spring 原理】Bean 的作用域与生命周期
java·后端·spring
我爱加班、、2 小时前
Websocket能携带token过去后端吗
前端·后端·websocket
一 乐2 小时前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
80530单词突击赢2 小时前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
vx1_Biye_Design3 小时前
基于Spring Boot+Vue的学生管理系统设计与实现-计算机毕业设计源码46223
java·vue.js·spring boot·spring·eclipse·tomcat·maven