Spring Boot過(guò)濾器的那些事:從配置到應(yīng)用場(chǎng)景
1. 什么是過(guò)濾器
過(guò)濾器是 Web 三大組件之一,也是項(xiàng)目中常用的工具。本文主要介紹過(guò)濾器的概念及在 Spring Boot 中的常用使用方法。
過(guò)濾器由 Servlet 提供,基于函數(shù)回調(diào)實(shí)現(xiàn)鏈?zhǔn)綄?duì)網(wǎng)絡(luò)請(qǐng)求和響應(yīng)的攔截與修改。由于基于 Servlet,幾乎可以攔截 Web 服務(wù)器管理的所有資源(JSP、圖片文件、HTML 文件、CSS 文件等)。
定義過(guò)濾器需要實(shí)現(xiàn)javax.servlet.Filter接口。過(guò)濾器不是 Servlet,無(wú)法直接生成對(duì)客戶端的響應(yīng),只能攔截已有請(qǐng)求并預(yù)處理不需要或不一致的信息資源。
2. 過(guò)濾器流程原理

在 Web 應(yīng)用中,可以開(kāi)發(fā)編寫多個(gè)過(guò)濾器,這些過(guò)濾器組合稱為過(guò)濾器鏈。用戶發(fā)起請(qǐng)求后,請(qǐng)求信息會(huì)按過(guò)濾器鏈中過(guò)濾器的順序依次進(jìn)入每個(gè)過(guò)濾器。經(jīng)過(guò)每層過(guò)濾器時(shí),需通過(guò)過(guò)濾器的校驗(yàn)邏輯并放行才能進(jìn)入下一層過(guò)濾器,直至服務(wù)器獲取資源。
服務(wù)器成功獲取資源并響應(yīng)過(guò)濾器后,會(huì)按反向順序經(jīng)過(guò)層層過(guò)濾器,最終響應(yīng)用戶。
3. 過(guò)濾器分類
Servlet 2.5:
- REQUEST: 用戶直接訪問(wèn)頁(yè)面時(shí),WEB 容器會(huì)調(diào)用過(guò)濾器鏈。
- FORWARD: 通過(guò) RequestDispatcher 的 forward 訪問(wèn)目標(biāo)資源時(shí)調(diào)用此過(guò)濾器。
- INCLUDE: 通過(guò) RequestDispatcher 的 include 方法調(diào)用目標(biāo)資源時(shí)調(diào)用。
- ERROR: 通過(guò)聲明式異常處理機(jī)制調(diào)用目標(biāo)資源時(shí)調(diào)用過(guò)濾器鏈。
Servlet 3.0:
- ASYNC: 支持異步處理。
4. 過(guò)濾器中需要實(shí)現(xiàn)的方法
public void doFilter(ServletRequest, ServletResponse, FilterChain): 實(shí)現(xiàn)實(shí)際過(guò)濾操作。當(dāng)客戶端請(qǐng)求方法與過(guò)濾器設(shè)置的 URL 匹配時(shí),Servlet 容器會(huì)先調(diào)用過(guò)濾器的 doFilter 方法。FilterChain 用于訪問(wèn)后續(xù)過(guò)濾器。public void init(FilterConfig filterConfig): Web 應(yīng)用啟動(dòng)時(shí),Web 服務(wù)器創(chuàng)建過(guò)濾器實(shí)例對(duì)象并調(diào)用其 init 方法完成對(duì)象初始化(過(guò)濾器對(duì)象僅創(chuàng)建一次,init 方法僅執(zhí)行一次)。開(kāi)發(fā)者可通過(guò) init 方法參數(shù)執(zhí)行讀取配置文件等初始化操作。public void destroy(): Servlet 容器銷毀過(guò)濾器實(shí)例前調(diào)用此方法。用于釋放過(guò)濾器占用的資源。
5. 創(chuàng)建過(guò)濾器的兩種方式
方法一:注解方式
創(chuàng)建步驟:
- 實(shí)現(xiàn)
Filter接口,添加@WebFilter和@Order注解配置過(guò)濾器:
@Order(1)
@WebFilter(filterName = "myFilter", urlPatterns = {"*"})
public class MyCustomFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {}
@Override
public void destroy() {}
}- 在啟動(dòng)類添加
@ServletComponentScan注解:
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}方法二:將過(guò)濾器注冊(cè)為 Bean
創(chuàng)建步驟:
- 創(chuàng)建實(shí)現(xiàn) Filter 接口的過(guò)濾器類:
public class MyCustomFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){}
@Override
public void destroy() {}
}- 創(chuàng)建過(guò)濾器配置類,注冊(cè)過(guò)濾器:
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean customFilter(){
FilterRegistrationBean<MyCustomFilter1> filterBean = new FilterRegistrationBean<>();
filterBean.setFilter(new MyCustomFilter1());
filterBean.setName("FilterController");
filterBean.addUrlPatterns("/*");
return filterBean;
}
}6. 注解方式的參數(shù)說(shuō)明與使用示例
(1)參數(shù)說(shuō)明
@WebFilter可配置多個(gè)參數(shù),部分參數(shù)說(shuō)明如下:
參數(shù)名稱 | 參數(shù)類型 | 參數(shù)描述 |
filterName | String | 過(guò)濾器的名稱 |
displayName | String | 要顯示的過(guò)濾器名稱 |
asyncSupported | boolean | 設(shè)置過(guò)濾器是否支持異步模式 |
initParams | WebInitParam[] | 你可以在初始化時(shí)配置一些參數(shù) |
servletNames | String[] | 設(shè)置要過(guò)濾的 Servlets |
urlPatterns | String[] | 指定要攔截的路徑 |
value | String[] | urlPatterns 屬性與 urlPatterns 屬性的作用相同,兩者都指定要攔截的路徑 |
dispatcherTypes | DispatcherType[] | 設(shè)置過(guò)濾器過(guò)濾的請(qǐng)求類型,支持以下屬性:ASYNC, ERROR, FORWARD, INCLUDE, REQUEST(默認(rèn)情況下,它過(guò)濾所有類型的請(qǐng)求) |
(2)使用示例
- 創(chuàng)建 Controller 類
@RestController
publicclass TestController {
@GetMapping("/a/hello")
public String hello1(){
return"hello world! a";
}
@GetMapping("/b/hello")
public String hello2(){
return"hello world! b";
}
@GetMapping("/c/hello")
public String hello3(){
return"hello world! c";
}
}- 創(chuàng)建過(guò)濾器類
@Order(1)
@WebFilter(filterName = "myFilter", urlPatterns = {"/a/*", "/b/*"}, description = "自定義過(guò)濾器")
publicclass MyCustomFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("過(guò)濾器初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("請(qǐng)求處理前...");
chain.doFilter(request, response); // 放行請(qǐng)求
System.out.println("請(qǐng)求處理后...");
}
@Override
public void destroy() {
System.err.println("過(guò)濾器銷毀");
}
}- 創(chuàng)建啟動(dòng)類
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}7. 過(guò)濾器注冊(cè) Bean 方式的參數(shù)說(shuō)明與使用示例
(1)方法參數(shù)說(shuō)明
方法名稱 | 方法描述 |
setName() | 設(shè)置過(guò)濾器的名稱。 |
setFilter() | 設(shè)置要注冊(cè)的過(guò)濾器。 |
setOrder() | 設(shè)置過(guò)濾器的順序位置。 |
setAsyncSupported() | 設(shè)置過(guò)濾器是否支持異步模式。 |
addUrlPatterns() | 添加攔截的路徑。 |
setUrlPatterns() | 設(shè)置攔截的路徑。 |
addServletNames() | 添加過(guò)濾器的 servlet 名稱。 |
setServletNames() | 設(shè)置注冊(cè)過(guò)濾器的 servlet 名稱。 |
setInitParameters() | 設(shè)置初始化參數(shù)。 |
addInitParameter() | 添加初始化參數(shù)。 |
setMatchAfter() | 設(shè)置是否在 Servlet 上下文中聲明的任何過(guò)濾器映射之后匹配過(guò)濾器映射。 |
setDispatcherTypes() | 設(shè)置過(guò)濾器過(guò)濾的請(qǐng)求類型。支持的屬性如下:ASYNC, ERROR, FORWARD, INCLUDE, REQUEST(默認(rèn)情況下,它過(guò)濾所有類型的請(qǐng)求)。 |
(2)使用示例
- 創(chuàng)建 Controller 類
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
publicclass TestController {
@GetMapping("/a/hello")
public String hello1(){
return"hello world! a";
}
@GetMapping("/b/hello")
public String hello2(){
return"hello world! b";
}
@GetMapping("/c/hello")
public String hello3(){
return"hello world! c";
}
}- 創(chuàng)建過(guò)濾器類
public class MyCustomFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("過(guò)濾器初始化");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("請(qǐng)求處理前...");
chain.doFilter(request, response); // 放行請(qǐng)求
System.out.println("請(qǐng)求處理后...");
}
@Override
public void destroy() {
System.err.println("過(guò)濾器銷毀");
}
}- 創(chuàng)建過(guò)濾器配置類
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean customFilter(){
FilterRegistrationBean<MyCustomFilter1> filterBean = new FilterRegistrationBean<>();
filterBean.setFilter(new MyCustomFilter1());
filterBean.setName("FilterController");
filterBean.addUrlPatterns("/c/*","/b/*");
return filterBean;
}
}- 創(chuàng)建啟動(dòng)類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}8. 過(guò)濾器使用場(chǎng)景
(1)日志記錄
過(guò)濾器可記錄請(qǐng)求和響應(yīng)的關(guān)鍵信息,便于排查問(wèn)題和分析系統(tǒng)運(yùn)行狀態(tài)。例如記錄請(qǐng)求 URL、參數(shù)、響應(yīng)狀態(tài)碼等。
(2)數(shù)據(jù)統(tǒng)計(jì)
用于采集各類數(shù)據(jù)指標(biāo),如統(tǒng)計(jì)請(qǐng)求次數(shù)、響應(yīng)時(shí)間分布等,為系統(tǒng)優(yōu)化提供依據(jù)。
(3)數(shù)據(jù)格式轉(zhuǎn)換
不同系統(tǒng)交互時(shí),過(guò)濾器可轉(zhuǎn)換數(shù)據(jù)格式,例如將 JSON 轉(zhuǎn)為 XML。
(4)為數(shù)據(jù)設(shè)置默認(rèn)值
檢查輸入數(shù)據(jù),為缺失字段設(shè)置默認(rèn)值,保證數(shù)據(jù)完整性。
(5)權(quán)限認(rèn)證、黑白名單
實(shí)現(xiàn)用戶權(quán)限認(rèn)證和訪問(wèn)控制,限制特定 IP 或用戶的訪問(wèn)。
(6)數(shù)據(jù)加解密、簽名驗(yàn)證
對(duì)敏感數(shù)據(jù)加解密以保證安全,同時(shí)進(jìn)行簽名驗(yàn)證確保數(shù)據(jù)完整性。


























