SpringBoot - 第三十八章 | 過濾器,監聽器,攔截器
在開發過程中,總存在著這樣的場景,比如攔截請求的ip地址,或者在所有的請求都返回相同的資料,如果每一個方法都寫出相同資料固然可以實現,但是隨著項目的變大,重複的代碼會越來越多,所以在這種情況我們可以用過濾器、監聽器、攔截器來實現以上功能。
過濾器(Filter)
過濾器Filter,是Servlet的的一個實用技術了。可通過過濾器,對請求進行攔截,比如讀取session判斷用戶是否登錄、判斷訪問的請求URL是否有訪問權限(黑白名單)等。主要還是可對請求進行預處理。接下來介紹下,在springboot如何實現過濾器功能。
@WebFilter
@WebFilter時Servlet3.0新增的註解,原先實現過濾器,需要在web.xml中進行配置,而現在通過此註解,啟動啟動時會自動掃描自動註冊。
建立 CustomFilter
修改 Chapter38Application
加入@ServletComponentScan
註解
測試結果
1 2 3 4 5 6 7 8 9 10 11
| 2019-04-27 19:41:43.526 INFO 683 --- [ main] c.j.l.s.chapter38.Chapter38Application : Starting Chapter38Application on localhost with PID 683 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38) 2019-04-27 19:41:43.530 INFO 683 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default 2019-04-27 19:41:44.589 INFO 683 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-04-27 19:41:44.619 INFO 683 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-04-27 19:41:44.619 INFO 683 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17] 2019-04-27 19:41:44.732 INFO 683 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-04-27 19:41:44.732 INFO 683 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1142 ms 2019-04-27 19:41:44.801 INFO 683 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化 2019-04-27 19:41:45.035 INFO 683 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-04-27 19:41:45.266 INFO 683 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-04-27 19:41:45.270 INFO 683 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.072 seconds (JVM running for 2.443)
|
過濾器已經生效了。但當註冊多個過濾器時,無法指定執行順序的,原本使用web。 xml配置過濾器時,是可指定執行順序的,但使用@WebFilter時,沒有這個配置屬性的(需要配合@Order進行),所以接下來介紹下通過FilterRegistrationBean進行過濾器的註冊。
通過過濾器的java類名稱,進行順序的約定,比如LogFilter和AuthFilter,此時AuthFilter就會比LogFilter先執行,因為首字母A比L前面。《關於@webFilter使用@Order無效問題》
FilterRegistrationBean方式
FilterRegistrationBean是springboot提供的,此類提供setOrder方法,可以為filter設置排序值,讓spring在註冊web filter之前排序後再依次註冊。
修改 CustomFilter
註解掉@WebFilter
1
| \\ @WebFilter(filterName = "customFilter", urlPatterns = {"/*"})
|
修改 Chapter38Application
啟動類中利用@bean註冊FilterRegistrationBean
測試結果
1 2 3 4 5 6 7 8 9 10 11
| 2019-04-27 20:12:49.425 INFO 772 --- [ main] c.j.l.s.chapter38.Chapter38Application : Starting Chapter38Application on localhost with PID 772 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38) 2019-04-27 20:12:49.428 INFO 772 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default 2019-04-27 20:12:50.615 INFO 772 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-04-27 20:12:50.646 INFO 772 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-04-27 20:12:50.646 INFO 772 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17] 2019-04-27 20:12:50.754 INFO 772 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-04-27 20:12:50.754 INFO 772 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1251 ms 2019-04-27 20:12:50.816 INFO 772 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化 2019-04-27 20:12:51.040 INFO 772 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-04-27 20:12:51.289 INFO 772 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-04-27 20:12:51.293 INFO 772 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.293 seconds (JVM running for 2.78)
|
監聽器(Listeeshi)
Listeeshi是servlet規範中定義的一種特殊類。用於監聽servletContext、HttpSession和servletRequest等域對象的建立和銷毀事件。監聽域對象的屬性發生修改的事件。用於在事件發生前、發生後做一些必要的處理。一般是獲取在線人數等業務需求。
建立 Customlister
修改 Chapter38Application
加入@ServletComponentScan
註解,進行自動註冊即可。
測試結果
啟動應用,http://localhost:8080
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 2019-04-27 20:20:46.638 INFO 784 --- [ main] c.j.l.s.chapter38.Chapter38Application : Starting Chapter38Application on localhost with PID 784 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38) 2019-04-27 20:20:46.641 INFO 784 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default 2019-04-27 20:20:47.837 INFO 784 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-04-27 20:20:47.870 INFO 784 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-04-27 20:20:47.870 INFO 784 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17] 2019-04-27 20:20:47.986 INFO 784 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-04-27 20:20:47.986 INFO 784 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1254 ms 2019-04-27 20:20:48.056 INFO 784 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化 2019-04-27 20:20:48.287 INFO 784 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-04-27 20:20:48.531 INFO 784 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-04-27 20:20:48.535 INFO 784 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.316 seconds (JVM running for 2.742) 2019-04-27 20:28:18.445 INFO 784 --- [nio-8080-exec-2] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化 2019-04-27 20:28:18.445 INFO 784 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化 2019-04-27 20:28:18.450 INFO 784 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2019-04-27 20:28:18.450 INFO 784 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2019-04-27 20:28:18.455 INFO 784 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms 2019-04-27 20:28:18.463 INFO 784 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理 2019-04-27 20:28:18.463 INFO 784 --- [nio-8080-exec-2] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理 2019-04-27 20:28:18.506 INFO 784 --- [nio-8080-exec-2] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀 2019-04-27 20:28:18.561 INFO 784 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀 2019-04-27 20:28:18.743 INFO 784 --- [nio-8080-exec-3] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化 2019-04-27 20:28:18.744 INFO 784 --- [nio-8080-exec-3] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理 2019-04-27 20:28:18.764 INFO 784 --- [nio-8080-exec-3] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀
|
攔截器(Interceptor)
以上的過濾器、監聽器都屬於Servlet的api,我們在開發中處理利用以上的進行過濾web請求時,還可以使用Spring提供的攔截器(HandlerInterceptor)進行更加精細的控制。
建立 CustomHandlerInterceptor
建立 WebMvcConfig
(注意spring boot 1.x 和 2.x使用方式略有不同)
測試結果
啟動應用,http://localhost:8080
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 2019-04-27 20:54:57.318 INFO 895 --- [ main] c.j.l.s.chapter38.Chapter38Application : Starting Chapter38Application on localhost with PID 895 (/Users/morose/Documents/workspace-SpringBoot/chapter-38/target/classes started by morose in /Users/morose/Documents/workspace-SpringBoot/chapter-38) 2019-04-27 20:54:57.323 INFO 895 --- [ main] c.j.l.s.chapter38.Chapter38Application : No active profile set, falling back to default profiles: default 2019-04-27 20:54:58.395 INFO 895 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2019-04-27 20:54:58.427 INFO 895 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2019-04-27 20:54:58.427 INFO 895 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17] 2019-04-27 20:54:58.542 INFO 895 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2019-04-27 20:54:58.542 INFO 895 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1154 ms 2019-04-27 20:54:58.614 INFO 895 --- [ main] c.j.l.s.chapter38.config.CustomFilter : filter 初始化 2019-04-27 20:54:58.858 INFO 895 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2019-04-27 20:54:59.115 INFO 895 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2019-04-27 20:54:59.118 INFO 895 --- [ main] c.j.l.s.chapter38.Chapter38Application : Started Chapter38Application in 2.092 seconds (JVM running for 2.457) 2019-04-27 20:55:01.684 INFO 895 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:初始化 2019-04-27 20:55:01.690 INFO 895 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2019-04-27 20:55:01.691 INFO 895 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2019-04-27 20:55:01.698 INFO 895 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms 2019-04-27 20:55:01.709 INFO 895 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.CustomFilter : doFilter 請求處理 2019-04-27 20:55:01.729 INFO 895 --- [nio-8080-exec-1] c.j.l.s.c.c.CustomHandlerInterceptor : 開始攔截登錄請求.... 2019-04-27 20:55:01.732 INFO 895 --- [nio-8080-exec-1] c.j.l.s.chapter38.config.Customlister : 監聽器:銷毀
|
請求鏈路說明
攔截器與過濾器的區別
攔截器是AOP( Aspect-Oriented Programming)的一種實現,底層通過動態代理模式完成。
(1)攔截器是基於java的反射機制的,而過濾器是基於函數回調。
(2)攔截器不依賴於servlet容器,而過濾器依賴於servlet容器。
(3)攔截器只能對Controller請求起作用,而過濾器則可以對幾乎所有的請求起作用。
(4)在Controller的生命週期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。
過濾器應用場景:設置編碼字符、過濾銘感字符
攔截器應用場景:攔截未登陸用戶、審計日誌
註:以上參考了
servlet/filter/listener/interceptor区别与联系
(十九)SpringBoot2.0整合拦截器
SpringBoot拦截器
oKong 的 SpringBoot | 第七章:过滤器、监听器、拦截器 文章。