先上代碼,下面的demo中包含多個攔截器、過濾器,以及切面的前置通知/后置通知/環繞通知:
https://gitee.com/xiaorenwu_dashije/filter_interceptor.git
下面總結一下相關原理:
首先了解一下SpringMVC的執行流程
具體流程如下
- 用戶發起請求到前端控制器(Controller)
- 前端控制器沒有處理業務邏輯的能力,需要找到具體的模型對象處理(Handler),到處理器映射器(HandlerMapping)中查找Handler對象(Model)。
- HandlerMapping返回執行鏈,包含了2部分內容: ① Handler對象、② 攔截器數組
- 前端處理器通過處理器適配器包裝后執行Handler對象。
- 處理業務邏輯。
- Handler處理完業務邏輯,返回ModelAndView對象,其中view是視圖名稱,不是真正的視圖對象。
- 將ModelAndView返回給前端控制器。
- 視圖解析器(ViewResolver)返回真正的視圖對象(View)。
- (此時前端控制器中既有視圖又有Model對象數據)前端控制器根據模型數據和視圖對象,進行視圖渲染。
- 返回渲染后的視圖(html/json/xml)返回。
- 給用戶產生響應。
核心就是DispatcherServlet核心控制器,我們看源碼可知道DispatcherServlet是Servlet的子類
下面用一張圖說一下過濾器、Servlet容器、攔截器、AOP、Controller之間的關系
然后具體執行流程如下:
攔截器和過濾器的區別
1、攔截器不依賴與servlet容器是SpringMVC自帶的,過濾器依賴於Servlet容器。
2、攔截器是基於java的反射機制的,而過濾器是基於函數回調。
3、攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
4、攔截器可以訪問controller上下文、值棧里的對象,而過濾器不能訪問。
(攔截器的preHandle方法在進入controller前執行,而攔截器的postHandle方法在執行完controller業務流程后,在視圖解析器解析ModelAndView之前執行,可以操控Controller的ModelAndView內容。而afterCompletion是在視圖解析器解析渲染ModelAndView完成之后執行的)
( 過濾器是在服務器啟動時就會創建的,只會創建一個實例,常駐內存,也就是說
服務器一啟動就會執行Filter的init(FilterConfig config)方法.當Filter被移除或服務器正常關閉時,會執行destroy方法)
5、攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器里注入一個service,可以調用業務邏輯。
(關於這句話的解讀是:我們知道攔截器是SprinMVC自帶的,而SpringMVC存在Controller層的,而controller層可以訪問到service層,service層是不能訪問service層的,而過濾器是客戶端和服務端之間請求與響應的過濾)
6、過濾器和攔截器觸發時機、時間、地方不一樣
(過濾器是在請求進入容器后,但請求進入servlet之前進行預處理的。請求結束返回也是在servlet處理完后,返回給前端之前,如果看不懂可以看7完后再來理解)
7、過濾器包裹住servlet,servlet包裹住攔截器。