今天將對SpringBoot中的攔截器interceptor從功能、實現(xiàn)、源碼等方面進行分析。
何為攔截器
攔截器嚣崭,在AOP(Aspect-Oriented Programming)中用于在某個方法或字段被訪問之前,進行攔截懦傍,然后在之前或之后加入某些操作雹舀。攔截是AOP的一種實現(xiàn)策略。
攔截器作用
日志記錄:記錄請求信息的日志粗俱,以便進行信息監(jiān)控说榆、信息統(tǒng)計、計算PV(Page View)等
權(quán)限檢查:如登錄檢測寸认,進入處理器檢測檢測是否登錄
性能監(jiān)控:通過攔截器在進入處理器之前記錄開始時間娱俺,在處理完后記錄結(jié)束時間,從而得到該請求的處理時間废麻。(反向代理荠卷,如apache也可以自動記錄);
通用行為:讀取cookie得到用戶信息并將用戶對象放入請求烛愧,從而方便后續(xù)流程使用油宜,還有如提取Locale掂碱、Theme信息等,只要是多個處理器都需要的即可使用攔截器實現(xiàn)慎冤。
攔截器實現(xiàn)
通過實現(xiàn)HandlerInterceptor接口疼燥,并重寫該接口的三個方法來實現(xiàn)攔截器的自定義。
接口 | 接口名稱 | 說明 |
---|---|---|
preHandle | 前置處理 | 在實際的Handle執(zhí)行前執(zhí)行蚁堤;有Boolean類型的返回值醉者,如果返回為False,則Handle本身及postHandle/afterCompletion以及后續(xù)的攔截器全部都不會再繼續(xù)執(zhí)行披诗;為True則反之撬即。 |
postHandle | 后置處理 | Handle執(zhí)行后視圖渲染前執(zhí)行 |
afterCompletion | 完成后處理 | Handle執(zhí)行且視圖渲染完成后執(zhí)行 |
運行流程如下:
- 攔截器執(zhí)行順序是按照Spring配置文件中定義的順序而定的。
- 會先按照順序執(zhí)行所有攔截器的preHandle方法呈队,一直遇到return false為止剥槐,比如第二個preHandle方法是return false,則第三個以及以后所有攔截器都不會執(zhí)行宪摧。若都是return true粒竖,則按順序加載完preHandle方法。
- 然后執(zhí)行主方法(自己的controller接口)几于,若中間拋出異常蕊苗,則跟return false效果一致,不會繼續(xù)執(zhí)行postHandle沿彭,只會倒序執(zhí)行afterCompletion方法岁歉。
-
在主方法執(zhí)行完業(yè)務(wù)邏輯(頁面還未渲染數(shù)據(jù))時,按倒序執(zhí)行postHandle方法膝蜈。若第三個攔截器的preHandle方法return false,則會執(zhí)行第二個和第一個的postHandle方法和afterCompletion(postHandle都執(zhí)行完才會執(zhí)行這個熔掺,也就是頁面渲染完數(shù)據(jù)后饱搏,執(zhí)行after進行清理工作)方法。(postHandle和afterCompletion都是倒序執(zhí)行)
攔截器運行流程
一般實現(xiàn)攔截器都是繼承HandlerInterceptorAdapter這個類置逻。這個類是實現(xiàn)AsyncHandlerInterceptor接口的抽象類推沸,而AsyncHandlerInterceptor又是繼承HandlerInterceptor的接口,額外提供了afterConcurrentHandlingStarted方法券坞,該方法是用來處理異步請求的鬓催。這個方法會在Controller方法異步執(zhí)行時開始執(zhí)行,而Interceptor的postHandle方法則是需要等到Controller的異步執(zhí)行完才能執(zhí)行恨锚。異步請求先支持preHandle宇驾、然后執(zhí)行afterConcurrentHandlingStarted。異步線程完成之后執(zhí)行preHandle猴伶、postHandle课舍、afterCompletion塌西。
這里來看一下HandlerInterceptorAdapter的源碼:
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.handler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* Abstract adapter class for the {@link AsyncHandlerInterceptor} interface,
* for simplified implementation of pre-only/post-only interceptors.
*
* @author Juergen Hoeller
* @since 05.12.2003
*/
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
/**
* This implementation always returns {@code true}.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
/**
* This implementation is empty.
*/
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
/**
* This implementation is empty.
*/
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
/**
* This implementation is empty.
*/
@Override
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}
可見HandlerInterceptorAdapter它“empty”地實現(xiàn)了三個HandlerInterceptor的三個方法和AsyncHandlerInterceptor新增的處理異步方法。如果實現(xiàn)HandlerInterceptor接口的話筝尾,三個方法必須實現(xiàn)捡需,不管需不需要,而HandlerInterceptorAdapter適配器筹淫,允許我們只實現(xiàn)需要的回調(diào)方法站辉,這應(yīng)該算是適配器設(shè)計模式的實現(xiàn)。
下面簡單創(chuàng)建一個自定義的攔截器demo损姜,繼承HandlerInterceptorAdapter饰剥。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("================================== preHandle1 ===========================================");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("================================== postHandle1 ===========================================");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("================================== afterCompletion1 ===========================================");
}
}
還需要創(chuàng)建一個配置類將該攔截器注入到spring容器中,這個配置類要實現(xiàn)WebMvcConfigurer薛匪。
(注意:繼承WebMvcConfigurerAdapter類這種方式官方建議廢棄)
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
}
}
HandlerInterceptor源碼
直接上翻譯后的源碼:
/**
* preHandle方法是進行處理器攔截用的捐川,顧名思義,該方法將在Controller處理之前進行調(diào)用逸尖,SpringMVC中的Interceptor攔截器是鏈式的古沥,可以同時存在
* 多個Interceptor,然后SpringMVC會根據(jù)聲明的前后順序一個接一個的執(zhí)行娇跟,而且所有的Interceptor中的preHandle方法都會在
* Controller方法調(diào)用之前調(diào)用岩齿。SpringMVC的這種Interceptor鏈式結(jié)構(gòu)也是可以進行中斷的,這種中斷方式是令preHandle的返
* 回值為false苞俘,當preHandle的返回值為false的時候整個請求就結(jié)束了盹沈。
*/
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
/**
* 這個方法只會在當前這個Interceptor的preHandle方法返回值為true的時候才會執(zhí)行。postHandle是進行處理器攔截用的吃谣,它的執(zhí)行時間是在處理器進行處理之
* 后乞封,也就是在Controller的方法調(diào)用之后執(zhí)行,但是它會在DispatcherServlet進行視圖的渲染之前執(zhí)行岗憋,也就是說在這個方法中你可以對ModelAndView進行操
* 作肃晚。這個方法的鏈式結(jié)構(gòu)跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會后調(diào)用仔戈,這跟Struts2里面的攔截器的執(zhí)行過程有點像关串,
* 只是Struts2里面的intercept方法中要手動的調(diào)用ActionInvocation的invoke方法,Struts2中調(diào)用ActionInvocation的invoke方法就是調(diào)用下一個Interceptor
* 或者是調(diào)用action监徘,然后要在Interceptor之前調(diào)用的內(nèi)容都寫在調(diào)用invoke之前晋修,要在Interceptor之后調(diào)用的內(nèi)容都寫在調(diào)用invoke方法之后。
*/
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
/**
* 該方法也是需要當前對應(yīng)的Interceptor的preHandle方法的返回值為true時才會執(zhí)行凰盔。該方法將在整個請求完成之后墓卦,也就是DispatcherServlet渲染了視圖執(zhí)行,
* 這個方法的主要作用是用于清理資源的户敬,當然這個方法也只能在當前這個Interceptor的preHandle方法的返回值為true時才會執(zhí)行趴拧。
*/
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
每一個攔截器都有一個preHandle()方法和postHandle()方法溅漾。在調(diào)用處理器之前后,都會調(diào)用攔截器著榴。由許多個攔截器組成一個執(zhí)行鏈添履,而這個執(zhí)行鏈是以數(shù)組的形式存在。所以脑又,執(zhí)行這個執(zhí)行鏈的中的所有攔截器的preHandle()方法是按照interceptor[]數(shù)組的正序執(zhí)行的暮胧,也就是按數(shù)組下標從小到大執(zhí)行每一個攔截器的preHandle()方法。而攔截器的postHandle()方法的執(zhí)行是按照逆序執(zhí)行的问麸,也就是按照interceptor[]數(shù)組的下標從大到小的順序執(zhí)行攔截器中的postHandle()方法往衷。而攔截器中的每一個afterCompletion()方法都是在渲染完視圖以后按照interceptor[]數(shù)組的下標從大到小的順序執(zhí)行攔截器中的afterCompletion()方法,也就是說afterCompletion()方法的執(zhí)行順序跟postHandle()方法的執(zhí)行順序是一樣的严卖。如下圖:
當然這是正常情況下的執(zhí)行順序席舍,但是當某一個攔截器的preHandle()方法()返回false,那么handler(處理器就不會執(zhí)行)。它會直接去掉用當前攔截器的前一個攔截器的afterCompletion()方法哮笆,從這個方法開始逆序執(zhí)行来颤。比如:這里的interceptor3的preHandle()方法返回false。那么就會直接調(diào)用interceptor2的afterCompletion()方法稠肘,并從這個方法開始逆序執(zhí)行至結(jié)束福铅。
HandlerInterceptor實現(xiàn)原理
下面結(jié)合SpringMVC來看一下攔截器的內(nèi)部實現(xiàn)。源碼上關(guān)鍵地方均加了注釋项阴。
首先滑黔,我們看一下 org.springframework.web.servlet.DispatcherServlet
中doDispatch方法,在這里可見執(zhí)行順序:preHandle->controller對應(yīng)的方法->postHandle->afterCompletion->afterConcurrentHandlingStarted环揽。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//調(diào)用已注冊HandlerInterceptor的preHandle()方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 真正執(zhí)行Controller對應(yīng)的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
//調(diào)用已注冊HandlerInterceptor的postHandle()方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//調(diào)用已注冊HandlerInterceptor的afterCompletion()方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//調(diào)用已注冊HandlerInterceptor的afterCompletion()方法
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
//調(diào)用已注冊HandlerInterceptor的afterConcurrentHandlingStarted()方法
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
/**
* Handle the result of handler selection and handler invocation, which is
* either a ModelAndView or an Exception to be resolved to a ModelAndView.
*/
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
//調(diào)用已注冊HandlerInterceptor的afterCompletion()方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
接下來看看 HandlerExecutionChain的applyPreHandle方法實現(xiàn):
/**
* 執(zhí)行注冊到該請求上的所有HandlerInterceptor的 preHandle 方法
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
}
return this.interceptors;
}
HandlerExecutionChain的applyPostHandle方法實現(xiàn):
* 執(zhí)行注冊到該請求上的所有HandlerInterceptor的 postHandle 方法
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
}
}
HandlerExecutionChain的triggerAfterCompletion方法實現(xiàn):
* 執(zhí)行注冊到該請求上的所有HandlerInterceptor的 afterCompletion 方法
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
最后略荡,HandlerExecutionChain的applyAfterConcurrentHandlingStarted方法實現(xiàn):
/**
* 執(zhí)行注冊到該請求上的所有AsyncHandlerInterceptor的 afterConcurrentHandlingStarted 方法
*/
void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = interceptors.length - 1; i >= 0; i--) {
if (interceptors[i] instanceof AsyncHandlerInterceptor) {
try {
AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
}
catch (Throwable ex) {
logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
}
}
}
}
}
接下來,HandlerExecutionChain 內(nèi)部的Interceptor數(shù)組是在什么時候初始化的呢歉胶?
來看看 HandlerExecutionChain 類的定義汛兜,源碼如下:
package org.springframework.web.servlet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
private HandlerInterceptor[] interceptors;
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}
public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
this.interceptorList = new ArrayList<HandlerInterceptor>();
CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
}
else {
this.handler = handler;
this.interceptors = interceptors;
}
}
/**
* 向handler中添加interceptor
*/
public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList().add(interceptor);
}
/**
* 向handler中添加多個interceptor
*/
public void addInterceptors(HandlerInterceptor... interceptors) {
if (!ObjectUtils.isEmpty(interceptors)) {
initInterceptorList().addAll(Arrays.asList(interceptors));
}
}
private List<HandlerInterceptor> initInterceptorList() {
if (this.interceptorList == null) {
this.interceptorList = new ArrayList<HandlerInterceptor>();
if (this.interceptors != null) {
// An interceptor array specified through the constructor
this.interceptorList.addAll(Arrays.asList(this.interceptors));
}
}
this.interceptors = null;
return this.interceptorList;
}
/**
* 按順序返回handler上的HandlerInterceptor列表
*/
public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
}
return this.interceptors;
}
}
HandlerExecutionChain 提供了addInterceptors()方法來添加HandlerInterceptor,那addInterceptors是在哪里被調(diào)用的呢跨扮?
回到DispatcherServlet 的 doDispatch方法中,如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 獲取當前請求對應(yīng)的handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
...
}
catch (Exception ex) {
dispatchException = 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 {
...
}
}
/**
* 獲取當前請求對應(yīng)的HandlerExecutionChain
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
接著來看看HandlerMapping 的getHandler(request)方法验毡,HandlerMapping是一個接口衡创,getHandler(request)方法是在AbstractHandlerMapping中實現(xiàn)的,如下:
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//獲取請求對應(yīng)的handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//根據(jù)handler構(gòu)造HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
/**
* 構(gòu)造HandlerExecutionChain, 并初始化HandlerInterceptor
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
可見晶通,在這里調(diào)用了addInterceptor璃氢,構(gòu)造HandlerExecutionChain并初始化HandlerInterceptor。
該方法就是從adaptedInterceptors屬性中狮辽,根據(jù)URL查找添加條件的Interceptor并組裝成HandlerExecutionChain并返回一也。
此處是否滿足條件的判斷是根據(jù)添加攔截器配置時調(diào)用的addPathPatterns方法決定的巢寡。
那么,要是還想繼續(xù)深究下去的話:
現(xiàn)在的問題就是adaptedInterceptors屬性是如何初始化的椰苟。
通過分析AbstractHandlerMapping類抑月,其adaptedInterceptors屬性實際是在initInterceptors方法中根據(jù)interceptors來進行初始化的。現(xiàn)在的問題轉(zhuǎn)變成interceptors這個屬性是如何初始化的了舆蝴。 實際上這個屬性是通過setInterceptors方法來設(shè)置的谦絮,但通過Alt+F7的搜索并未搜索到該方法是在哪個地方調(diào)用的。
我們換個思路洁仗,通過@EnableWebMvc來分析看通過addInterceptors方法配置的Interceptor在到底添加到哪去了层皱。
前言已經(jīng)分析,通過@EnableWebMvc注解實際上引入了DelegatingWebMvcConfiguration這個類赠潦;查看這個類叫胖,在其中有一方法被Autowired注解:
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
通過查看Autowired注解定義,了解到當它使用在List參數(shù)的方法上時她奥,會查找List所包含的對象類型的所有Bean然后進行注入瓮增。這也意味著,此處會將所有實現(xiàn)WebMvcConfigurer接口的類進行注入方淤,然后添加到configurers屬性中去钉赁;在此處,我們自定義的繼承自WebMvcConfigurer的類會被注入携茂。
再查看 DelegatingWebMvcConfiguration 這個類你踩,它繼承了 WebMvcConfigurationSupport 類。分析WebMvcConfigurationSupport讳苦,可以看到以下方法:
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());
PathMatchConfigurer configurer = getPathMatchConfigurer();
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
mapping.setPathMatcher(pathMatcher);
}
return mapping;
}
可以看到RequestMappingHandlerMapping類被注入Spring容器带膜。
同時通過mapping.setInterceptors(getInterceptors())將所有的Interceptors設(shè)置到HandperMapping對象中 。
這樣就找到了ReuqestMappingHandlerMapping的setInterceptors方法調(diào)用處了鸳谜。
接下來的問題就是此處調(diào)用的getInterceptors方法的實現(xiàn):
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
此處如果interceptors對象為空時膝藕,會調(diào)用addInterceptors方法;其實現(xiàn)在DelegatingWebMvcConfiguration類中:
protected void addInterceptors(InterceptorRegistry registry) {
this.configurers.addInterceptors(registry);
}
在前文已經(jīng)描述到咐扭,DelegatingWebMvcConfiguration類中的configurers屬性會將所有繼承了WebMvcConfigurer的配置類全部添加進去芭挽。如我們自定義的配置類;在此處調(diào)用DelegatingWebMvcConfiguration的addInterceptors方法時蝗肪,實際就是調(diào)用各個WebMvcConfigurer對象的addInterceptors方法來完成自定義的Interceptor注冊過程袜爪。
通過這一系列過程,RequestMappingHandlerMapping的getInterceptors方法就可以獲取到所有自定義的Interceptor了薛闪。
完事辛馆!
注:
實現(xiàn)原理部分參考結(jié)合了http://www.reibang.com/p/b849f9919130和https://blog.csdn.net/icarusliu/article/details/78833520,兩位作者正好各分析了上半段和下半段的源碼豁延。