精盡Spring MVC原始碼分析 - HandlerMapping 元件(二)之 HandlerInterceptor 攔截器
阿新 • • 發佈:2020-12-16
> 該系列文件是本人在學習 Spring MVC 的原始碼過程中總結下來的,可能對讀者不太友好,請結合我的原始碼註釋 [Spring MVC 原始碼分析 GitHub 地址](https://github.com/liu844869663/spring-framework) 進行閱讀
>
> Spring 版本:5.2.4.RELEASE
>
> 該系列其他文件請檢視:[**《精盡 Spring MVC 原始碼分析 - 文章導讀》**](https://www.cnblogs.com/lifullmoon/p/14123963.html)
## HandlerMapping 元件
HandlerMapping 元件,請求的**處理器匹配器**,負責為請求找到合適的 `HandlerExecutionChain` 處理器執行鏈,包含處理器(`handler`)和攔截器們(`interceptors`)
- `handler` 處理器是 Object 型別,可以將其理解成 HandlerMethod 物件(例如我們使用最多的 `@RequestMapping` 註解所標註的方法會解析成該物件),包含了方法的所有資訊,通過該物件能夠執行該方法
- `HandlerInterceptor` 攔截器對處理請求進行**增強處理**,可用於在執行方法前、成功執行方法後、處理完成後進行一些邏輯處理
由於 HandlerMapping 元件涉及到的內容比較多,考慮到內容的排版,所以將這部分內容拆分成了四個模組,依次進行分析:
- [**《HandlerMapping 元件(一)之 AbstractHandlerMapping》**](https://www.cnblogs.com/lifullmoon/p/14137308.html)
- [**《HandlerMapping 元件(二)之 HandlerInterceptor 攔截器》**](https://www.cnblogs.com/lifullmoon/p/14137358.html)
- **《HandlerMapping 元件(三)之 AbstractHandlerMethodMapping》**
- **《HandlerMapping 元件(四)之 AbstractUrlHandlerMapping》**
## HandlerMapping 元件(二)之 HandlerInterceptor 攔截器
在上一篇[**《HandlerMapping 元件(一)之 AbstractHandlerMapping》**](https://www.cnblogs.com/lifullmoon/p/14137308.html)文件中分析了 HandlerMapping 元件的 AbstractHandlerMapping 抽象類,在獲取`HandlerExecutionChain` 處理器執行鏈時,會去尋找匹配的 HandlerInterceptor 攔截器們,並新增到其中。那麼本文將分享 Spring MVC 的攔截器相關內容
### HandlerInterceptor
`org.springframework.web.servlet.HandlerInterceptor`,處理器攔截器介面,程式碼如下:
```java
public interface HandlerInterceptor {
/**
* 前置處理,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 執行之前
*/
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
/**
* 後置處理,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 執行成功之後
*/
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
/**
* 完成處理,在 {@link HandlerAdapter#handle(HttpServletRequest, HttpServletResponse, Object)} 執行之後(無論成功還是失敗)
* 條件:執行 {@link #preHandle(HttpServletRequest, HttpServletResponse, Object)} 成功的攔截器才會執行該方法
*/
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
```
### HandlerExecutionChain
`org.springframework.web.servlet.HandlerExecutionChain`,處理器執行鏈,也就是通過 HandlerMapping 元件為請求找到的處理物件,包含處理器(`handler`)和攔截器們(`interceptors`)
#### 構造方法
```java
public class HandlerExecutionChain {
/**
* 處理器
*/
private final Object handler;
/**
* 攔截器陣列
*/
@Nullable
private HandlerInterceptor[] interceptors;
/**
* 攔截器陣列。
*
* 在實際使用時,會呼叫 {@link #getInterceptors()} 方法,初始化到 {@link #interceptors} 中
*/
@Nullable
private List interceptorList;
/**
* 已成功執行 {@link HandlerInterceptor#preHandle(HttpServletRequest, HttpServletResponse, Object)} 的位置
*
* 在 {@link #applyPostHandle} 和 {@link #triggerAfterCompletion} 方法中需要用到,用於倒序執行攔截器的方法
*/
private int interceptorIndex = -1;
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList<>();
// 將原始的 HandlerExecutionChain 的 interceptors 複製到 this.interceptorList 中
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
// 將入參的 interceptors 合併到 this.interceptorList 中
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
} else {
this.handler = handler;
this.interceptors = interceptors;
}
}
}
```
- `handler`:請求對應的處理器物件,可以先理解為 `HandlerMethod` 物件(例如我們常用的 `@RequestMapping` 註解對應的方法會解析成該物件),也就是我們的某個 Method 的所有資訊,可以被執行
- `interceptors`:請求匹配的攔截器陣列
- `interceptorList`:請求匹配的攔截器集合,至於為什麼要該屬性,我還沒看明白