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)采用的设计模式
-
责任链模式(Chain of Responsibility)
- 多个 Filter 形成链式调用,每个 Filter 可以决定是否继续传递请求到下一个环节
- 示例代码体现:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {// 前置处理chain.doFilter(request, response); // 传递到下一个过滤器或Servlet// 后置处理 }
-
装饰器模式(Decorator)
- 通过 Filter 包装原始请求/响应对象,增强其功能(如字符编码处理)
- 示例:
CharacterEncodingFilter
装饰请求对象以设置字符编码
拦截器(Interceptor)采用的设计模式
-
AOP(面向切面编程)
- 拦截器本质是 Spring AOP 的一种实现,通过对 Handler 方法的环绕通知实现增强
- 示例:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {// 前置处理,返回true继续执行后续拦截器和Handlerreturn true; }
-
观察者模式(Observer)
- 拦截器的
postHandle
和afterCompletion
方法类似于事件监听机制 - 当请求处理完成或发生异常时,触发相应的回调方法
- 拦截器的
典型应用场景对比
场景 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
请求编码处理 | CharacterEncodingFilter | - |
跨域请求处理 | CorsFilter | - |
权限校验 | 基于 Servlet API 的简单权限检查 | 基于 Spring Security 的复杂权限控制 |
请求日志记录 | 记录原始请求信息 | 记录完整的处理时间和结果 |
事务管理 | - | 基于 @Transactional 注解的事务拦截 |
性能监控 | 统计请求总耗时 | 统计 Controller 方法执行耗时 |
选择建议
- 使用过滤器:需要对所有请求进行统一处理(如编码、安全头设置)
- 使用拦截器:需要访问 Spring 容器中的 Bean 或处理 MVC 相关对象(如 ModelAndView)
- 组合使用:复杂场景下,可结合过滤器和拦截器实现多层级处理(如:过滤器处理基础安全,拦截器处理业务权限)
下面将详细介绍Spring Boot中过滤器(Filter)和拦截器(Interceptor)的使用方法,并提供示例代码:
一、过滤器(Filter)的使用步骤
1. 创建Filter类并实现Filter接口
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 {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;// 前置处理:记录请求信息System.out.println("Filter: 请求URL - " + httpRequest.getRequestURI());// 传递请求到下一个过滤器或Servletchain.doFilter(request, response);// 后置处理:记录响应信息System.out.println("Filter: 请求处理完成");}
}
2. 启用Servlet组件扫描(如果未使用@ServletComponentScan)
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(推荐方式)
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class FilterConfig {@Beanpublic FilterRegistrationBean<RequestLogFilter> loggingFilter() {FilterRegistrationBean<RequestLogFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new RequestLogFilter());registrationBean.addUrlPatterns("/*"); // 拦截所有请求registrationBean.setOrder(1); // 设置过滤器执行顺序return registrationBean;}
}
二、拦截器(Interceptor)的使用步骤
1. 创建Interceptor类并实现HandlerInterceptor接口
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<>();@Overridepublic 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}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) {// 后置处理:Controller方法执行完成后,但视图渲染前System.out.println("Interceptor: 请求处理中 - " + request.getRequestURI());}@Overridepublic 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
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 {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new RequestTimeInterceptor()).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/static/**", "/error"); // 排除静态资源和错误页面}
}
三、过滤器 vs 拦截器执行顺序示例
执行顺序配置
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic 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 {@Beanpublic FilterRegistrationBean<FirstFilter> firstFilter() {FilterRegistrationBean<FirstFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new FirstFilter());registration.addUrlPatterns("/*");registration.setOrder(1); // 过滤器顺序1return registration;}@Beanpublic FilterRegistrationBean<SecondFilter> secondFilter() {FilterRegistrationBean<SecondFilter> registration = new FilterRegistrationBean<>();registration.setFilter(new SecondFilter());registration.addUrlPatterns("/*");registration.setOrder(2); // 过滤器顺序2return registration;}
}
执行顺序结果
对于一个HTTP请求,执行顺序为:
FirstFilter.pre -> SecondFilter.pre ->
FirstInterceptor.pre -> SecondInterceptor.pre ->
Controller处理请求 ->
SecondInterceptor.post -> FirstInterceptor.post ->
视图渲染 ->
SecondInterceptor.after -> FirstInterceptor.after ->
SecondFilter.post -> FirstFilter.post
四、常见应用场景代码示例
1. 权限校验拦截器
public class AuthInterceptor implements HandlerInterceptor {@Overridepublic 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. 字符编码过滤器
@WebFilter(urlPatterns = "/*", filterName = "encodingFilter")
public class EncodingFilter implements Filter {@Overridepublic 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 | 可直接注入所需组件 |
六、注意事项
-
过滤器注意点:
- Filter由Servlet容器管理,生命周期独立于Spring
- 无法直接注入Spring Bean,需通过ApplicationContext获取
- 对所有请求生效,包括静态资源和错误请求
-
拦截器注意点:
- Interceptor由Spring管理,可使用依赖注入
- 仅拦截Spring MVC处理的请求,对静态资源无效
- 可访问HandlerMethod、ModelAndView等Spring MVC特有对象
-
性能考虑:
- 过滤器执行更早,性能开销更小
- 拦截器功能更强大,但依赖Spring MVC上下文
根据实际需求合理选择过滤器或拦截器,复杂场景可组合使用两者。