DispatcherServlet的doDispatch方法在調(diào)用處理器處理請求前后分別調(diào)用了攔截器的前置和后置處理方法,代碼如下所示:
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
processDispatchResult方法在渲染后調(diào)用了攔截器的完成處理方法:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
// 省略一些代碼
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
不管調(diào)用攔截器的哪個方法,都與攔截器自己和HandlerExecutionChain相關(guān),本文接下來分析攔截器和HandlerExecutionChain。
攔截器HandlerInterceptor
攔截器接口HandlerInterceptor允許定制化請求的處理過程,其代碼如下所示:
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
}
三個接口方法的用途和區(qū)別如下:
- preHandle前置處理方法在處理器被調(diào)用前執(zhí)行,只有返回true時后續(xù)攔截器的前置處理方法才會執(zhí)行;
- postHandle后置處理方法在處理器被調(diào)用后且渲染前執(zhí)行,會按添加的順序逆序執(zhí)行;
- afterCompletion完成處理方法在請求處理完成后即渲染后執(zhí)行,同樣會按添加的順序逆序執(zhí)行,注意只有前置處理方法返回true時該方法才會被執(zhí)行。
HandlerExecutionChain
在分析HandlerMapping時提到,HandlerMapping的getHandler會將匹配的處理器和攔截器包裝成HandlerExecutionChain并返回,接下來看一下HandlerExecutionChain類。
成員變量
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;
}
}
public Object getHandler() {
return this.handler;
}
public void addInterceptor(HandlerInterceptor interceptor) {
initInterceptorList().add(interceptor);
}
public void addInterceptors(HandlerInterceptor... interceptors) {
if (!ObjectUtils.isEmpty(interceptors)) {
CollectionUtils.mergeArrayIntoCollection(interceptors, initInterceptorList());
}
}
private List<HandlerInterceptor> initInterceptorList() {
if (this.interceptorList == null) {
this.interceptorList = new ArrayList<HandlerInterceptor>();
if (this.interceptors != null) {
// An interceptor array specified through the constructor
CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
}
}
this.interceptors = null;
return this.interceptorList;
}
public HandlerInterceptor[] getInterceptors() {
if (this.interceptors == null && this.interceptorList != null) {
this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
}
return this.interceptors;
}
// 省略一些代碼
}
- handler即是已匹配的處理器對象;
- interceptors和interceptorList都用來保存關(guān)聯(lián)的攔截器,前者是數(shù)組,后者是列表;
- interceptorIndex是一個索引,下面會看到其作用。
請求前置處理
HandlerExecutionChain的前置處理方法在處理器對象handler被調(diào)用前執(zhí)行,它會調(diào)用所有與該HandlerExecutionChain關(guān)聯(lián)的攔截器的前置處理方法:
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;
}
- 各攔截器的前置處理方法preHandle按添加順序依次被調(diào)用,若其中某個攔截器返回false則終止攔截器鏈的執(zhí)行過程,觸發(fā)請求完成處理;
- interceptorIndex變量保存的是preHandle方法已執(zhí)行且返回true的攔截器在數(shù)組中的索引;
- 只有HandlerExecutionChain的前置處理方法返回true后處理器才會被真正調(diào)用。
請求后置處理
HandlerExecutionChain的后置處理方法在處理器被調(diào)用后、渲染之前執(zhí)行,它會調(diào)用所有與該HandlerExecutionChain關(guān)聯(lián)的攔截器的后置處理方法:
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);
}
}
}
- 各攔截器的后置處理方法postHandle按添加順序反向依次被調(diào)用。
請求完成處理
HandlerExecutionChain的完成處理方法在請求處理完成后即渲染之后執(zhí)行,它會調(diào)用所有與該HandlerExecutionChain關(guān)聯(lián)的preHandle方法已執(zhí)行且返回true的攔截器的完成處理方法:
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);
}
}
}
}
- interceptorIndex變量在這里發(fā)揮作用,所以triggerAfterCompletion與applyPostHandle的區(qū)別是前者不會觸發(fā)所有的攔截器,只觸發(fā)preHandle方法已執(zhí)行且返回true的攔截器,而后者會觸發(fā)所有的攔截器;
- preHandle方法已執(zhí)行且返回true的各攔截器的完成處理方法afterCompletion按添加順序反向被調(diào)用。
添加攔截器
在Spring中可以繼承WebMvcConfigurerAdapter類并重寫addInterceptors方法添加所需的攔截器:
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyIntercepter());
}
}
總結(jié)
至此,我們終于大概知道了Spring MVC對請求的處理過程,在這其中更深入地了解了Spring MVC的運(yùn)行機(jī)制和擴(kuò)展接口,也看到了諸如模板方法模式、策略模式和組合模式等設(shè)計模式的實(shí)際運(yùn)用。