1. 过滤器的基础概念
1.1 什么是过滤器?
- Servlet 规范的一部分,定义在
javax.servlet.Filter
接口中。 - 在 HTTP 请求到达目标资源(如 Controller)之前或响应返回客户端之前,拦截并对其进行预处理或后处理。
1.2 过滤器的核心方法
javax.servlet.Filter
接口定义了以下三个方法:
-
init(FilterConfig filterConfig)
- 在过滤器初始化时调用,通常用于加载资源或初始化配置。
-
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- 核心方法,用于拦截和处理请求或响应。
- 调用
chain.doFilter(request, response)
表示将请求传递给下一个过滤器或目标资源。
-
destroy()
- 在过滤器销毁时调用,用于释放资源。
2. Spring Boot 项目中如何使用过滤器
在 Spring Boot 中,可以通过以下两种方式注册过滤器:
2.1 自动注册过滤器
通过 @Component
注解将过滤器注册为 Spring Bean,Spring Boot 会自动加载并将其添加到过滤器链中。
示例代码:
import org.springframework.stereotype.Component;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;@Component
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) {System.out.println("过滤器初始化");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;System.out.println("请求路径:" + httpRequest.getRequestURI());chain.doFilter(request, response); // 继续传递请求}@Overridepublic void destroy() {System.out.println("过滤器销毁");}
}
解释:
@Component
:- 将该类注册为 Spring Bean,Spring Boot 自动将其作为过滤器加载。
- 默认拦截所有请求(
/*
)。
doFilter
方法:HttpServletRequest
用于获取请求的详细信息(如路径、参数)。chain.doFilter
表示继续将请求传递给下一个过滤器或目标资源。
2.2 手动注册过滤器
通过 FilterRegistrationBean
手动注册过滤器,可以指定 URL 匹配规则和执行顺序。
示例代码:
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<MyFilter> registerMyFilter() {FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new MyFilter()); // 注册过滤器registrationBean.addUrlPatterns("/api/*"); // 仅拦截 /api/ 开头的请求registrationBean.setOrder(1); // 设置执行顺序,值越小优先级越高return registrationBean;}
}
解释:
FilterRegistrationBean
:- 用于手动注册过滤器,提供灵活的配置选项。
addUrlPatterns
:- 定义过滤器的作用范围,比如这里仅拦截
/api/*
的请求。
- 定义过滤器的作用范围,比如这里仅拦截
setOrder
:- 定义过滤器的执行顺序,值越小优先级越高。
3. 使用 Spring 提供的扩展过滤器
Spring 提供了一个扩展类 OncePerRequestFilter
,它是对标准过滤器的增强,用于确保在一次请求中只执行一次过滤逻辑(防止重复过滤)。
示例代码:
import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class MyOncePerRequestFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {System.out.println("请求路径:" + request.getRequestURI());filterChain.doFilter(request, response); // 继续传递请求}
}
注册方式: 可以通过 @Component
或 FilterRegistrationBean
注册,方式与标准过滤器一致。
解释:
OncePerRequestFilter
:- 确保在一次请求中只执行一次过滤器逻辑。
doFilterInternal
:- 处理请求的核心方法,逻辑和标准
Filter
的doFilter
类似。
- 处理请求的核心方法,逻辑和标准
4. 过滤器的执行顺序
在 Spring Boot 中,多个过滤器的执行顺序由以下规则决定:
4.1 自动注册的过滤器:
示例:
@Component
@Order(1) // 优先级最高
public class FirstFilter implements Filter {...
}@Component
@Order(2) // 优先级次之
public class SecondFilter implements Filter {...
}
- 默认按加载顺序执行。
- 可以通过
@Order
注解设置优先级(值越小优先级越高)。
4.2 手动注册的过滤器:
示例:
registrationBean.setOrder(1);
- 使用
FilterRegistrationBean#setOrder
方法设置优先级。
5. 常见过滤器应用场景
-
用户认证和授权
- 检查请求头中是否携带有效的 Token。
- 验证用户权限。
-
请求日志记录
示例:
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;System.out.println("请求路径:" + httpRequest.getRequestURI());chain.doFilter(request, response); }
- 记录请求的详细信息(如路径、IP 地址、参数)。
-
跨域处理
示例:
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletResponse httpResponse = (HttpServletResponse) response;httpResponse.setHeader("Access-Control-Allow-Origin", "*");httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");chain.doFilter(request, response); }
- 在响应头中添加跨域支持信息。
-
加解密
- 对请求体进行解密,对响应体进行加密。
6. 注意事项
-
避免业务逻辑的复杂化:
- 过滤器应专注于全局性逻辑(如日志、认证),复杂的业务逻辑应放在 Service 层处理。
-
避免重复过滤:
- 使用
OncePerRequestFilter
防止在同一个请求中多次执行过滤器逻辑。
- 使用
-
路径匹配规则:
- 通过
addUrlPatterns
或在doFilter
中手动判断,确保过滤器只作用于必要的路径。
- 通过
-
资源拦截控制:
- 排除静态资源(如
.css
,.js
)的拦截,避免对静态资源应用不必要的逻辑。
- 排除静态资源(如
7.一个请求在整个Spring Boot Web 应用中的处理流程
以一个常见的 Spring Boot Web 应用为例,处理一个请求可能会经过多个环节:
[客户端请求] ↓
[Filter1 -> Filter2 -> ... -> FilterN] // 过滤器链↓
[Servlet Container] // DispatcherServlet↓
[Spring MVC 拦截器(Interceptor)] // 可选↓
[Controller / RestController 方法]↓
[视图解析或返回响应]↑
[FilterN -> ... -> Filter1] // 响应回程,也可以在过滤器里做后置处理↑
[客户端接收响应]
- 过滤器链先于 Spring MVC 的拦截器执行。
- 在
Filter.doFilter
中,如果调用chain.doFilter(request, response)
,请求才会进入下一个过滤器或目标 Servlet。 - 响应返回时,也会逆向经过过滤器链,为我们提供后置处理的机会。