一、前言
在 DispatcherServlet 中的 doDispatch 方法中,我們發(fā)現(xiàn)調(diào)用 getHandler() 方法返回的不是一個純HandlerMethod,而是一個HandlerExecutionChain,這個是為啥呢?因為在執(zhí)行 真正的處理方法前后,會執(zhí)行一下默認攔截器或者自定義攔截器。接下來就慢慢的揭開她的面紗。
二、重溫 doDispatch
首先在回顧一下 doDispatch 方法,請看源碼
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//省略代碼....
try {
//省略代碼....
try {
//省略代碼....
// Determine handler for the current request.
//獲取Handler執(zhí)行鏈
mappedHandler = getHandler(processedRequest);
//省略代碼....
//執(zhí)行攔截器方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 執(zhí)行真實的處理方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//省略代碼....
applyDefaultViewName(processedRequest, mv);
//執(zhí)行攔截器方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
}catch (Throwable err) {
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}else {
}
}
}

主要代碼說明:
- mappedHandler = getHandler(processedRequest); 獲取 HandlerExecutionChain 。
- mappedHandler.applyPreHandle(processedRequest, response) 執(zhí)行Handler的前置方法。
- mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 執(zhí)行真正的 處理方法
- mappedHandler.applyPostHandle(processedRequest, response, mv); 執(zhí)行攔擊去的后置方法
- triggerAfterCompletion(processedRequest, response, mappedHandler, ex); 執(zhí)行攔截器的完成方法
三、攔截器介紹
1、首先查看攔截的接口繼承關系圖

?
根據(jù)繼承關系圖發(fā)現(xiàn),連接器的頂級接口為 HandlerInterceptor ,不過SpringMVC在也提供了一個適配器類 HandlerInterceptorAdapter,在擴展自己的攔截器時,直接繼承 HandlerInterceptorAdapter 即可,直接重寫,需要關注的方法就行。
2、看看 HandlerInterceptor 都有哪些方法
public interface HandlerInterceptor {
//前置方法, 獲取到 Handler執(zhí)行真正的 handler之前
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
//執(zhí)行完真正的handler之后
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
// 視圖渲染之后
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}

HandlerInterceptor接口一共提供了三個接口分別為
- 獲取到Handler適配器,調(diào)用真正的 Handler處理類之前
- 執(zhí)行完真正的Handler處理類,但在視圖渲染之前
- 視圖渲染之后
三、Spring是如何裝載攔截器
1、XML 配置方式
在通通過 <mvc:interceptors> 方式配置攔截器,此方式是通過 標簽解析類 InterceptorsBeanDefinitionParser 完成的,具體如源碼所示

?
2、SpringBoot注解方式
SpringBoot的的方式是需要先創(chuàng)建實現(xiàn)接口 WebMvcConfigurer 的自定也配置類,并且重寫addInterceptors方法,如下所示:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//實現(xiàn)此方法,注冊自定義攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTHandlerInterceptor());
registry.addWebRequestInterceptor(new TestWebRequestInterceptor());
}
}

此處注冊了攔截器,那么在真正執(zhí)行時,又是如何獲取攔截器的呢?
在上篇介紹 Spring MVC 源碼分析之 加載及查找 Controller 說明 RequestMappingHandlerMapping 的創(chuàng)建時,有說明??梢宰孕胁榭础?/p>
四、執(zhí)行順序
如果自定義了多個攔截器,如何使其按自己的順序執(zhí)行呢,這個在 WebMvcConfigurer中注冊攔截器時,可以按照自己的執(zhí)行順序進行注冊,有一點需要注意,在攔截器中執(zhí)行 preHandle 方法是按注冊順序執(zhí)行,在執(zhí)行 postHandle 方法時是按照注冊的倒序進行執(zhí)行的。
攔截器的注冊順序為 攔截器1,攔截器2,攔截器3,
執(zhí)行 preHandle 方法的順序為:攔截器1 =》攔截器2 =》 攔截器3
執(zhí)行 postHandle 方法的順序為:攔截器3 =》攔截器2 =》 攔截器1
五、總結
此篇文章主要介紹了,攔截器的注冊執(zhí)行等,介紹的比較粗糙,主要為了記錄一下自己的源碼分析。望大拿斧正。