SpringMVC 請求處理 - HandlerInterceptor
對SpringMVC有所瞭解的人肯定接觸過HandlerInterceptor攔截器,HandlerInterceptor介面給我們提供了3個方法:
(1)preHandle: 在執行controller處理之前執行,返回值為boolean ,返回值為true時接著執行postHandle和afterCompletion,如果我們返回false則中斷執行
(2)postHandle:在執行controller的處理後,在ModelAndView處理前執行
(3)afterCompletion :在DispatchServlet執行完ModelAndView之後執行
原始碼如下:
public interface HandlerInterceptor { /** * preHandle方法是進行處理器攔截用的,顧名思義,該方法將在Controller處理之前進行呼叫,SpringMVC中的Interceptor攔截器是鏈式的,可以同時存在 * 多個Interceptor,然後SpringMVC會根據宣告的前後順序一個接一個的執行,而且所有的Interceptor中的preHandle方法都會在 * Controller方法呼叫之前呼叫。SpringMVC的這種Interceptor鏈式結構也是可以進行中斷的,這種中斷方式是令preHandle的返 * 回值為false,當preHandle的返回值為false的時候整個請求就結束了。 */ boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** * 這個方法只會在當前這個Interceptor的preHandle方法返回值為true的時候才會執行。postHandle是進行處理器攔截用的,它的執行時間是在處理器進行處理之 * 後,也就是在Controller的方法呼叫之後執行,但是它會在DispatcherServlet進行檢視的渲染之前執行,也就是說在這個方法中你可以對ModelAndView進行操 * 作。這個方法的鏈式結構跟正常訪問的方向是相反的,也就是說先宣告的Interceptor攔截器該方法反而會後呼叫,這跟Struts2裡面的攔截器的執行過程有點像, * 只是Struts2裡面的intercept方法中要手動的呼叫ActionInvocation的invoke方法,Struts2中呼叫ActionInvocation的invoke方法就是呼叫下一個Interceptor * 或者是呼叫action,然後要在Interceptor之前呼叫的內容都寫在呼叫invoke之前,要在Interceptor之後呼叫的內容都寫在呼叫invoke方法之後。 */ void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; /** * 該方法也是需要當前對應的Interceptor的preHandle方法的返回值為true時才會執行。該方法將在整個請求完成之後,也就是DispatcherServlet渲染了檢視執行, * 這個方法的主要作用是用於清理資源的,當然這個方法也只能在當前這個Interceptor的preHandle方法的返回值為true時才會執行。 */ void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
我們可以看到這三個方法的呼叫過程是不一樣的,接下來我們分析一下這個三個方法具體呼叫實現的地方。其最終實現呼叫的地方是在doDispatch函式中,因為doDispatch完成了一個請求到返回資料的完整操作。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain mappedHandler = null; ....... try { ModelAndView mv = null; Exception dispatchException = null; try { ....... //獲取HandlerExecutionChain mappedHandler = getHandler(processedRequest); ...... //最終會呼叫HandlerInterceptor的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 呼叫具體的Controller中的處理方法Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ...... //最終會呼叫HandlerInterceptor的postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //最終會呼叫HandlerInterceptor的afterCompletion 方法 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { //最終會呼叫HandlerInterceptor的afterCompletion 方法 triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
mappedHandler.applyPreHandle(processedRequest, response):最終會呼叫HandlerInterceptor的preHandle方法。在HandlerExecutionChain中的具體實現如下,我們可以看到會呼叫所有的HandlerInterceptor攔截器並呼叫其preHandler方法。
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)) {//分別呼叫攔截器的preHandle方法
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
mappedHandler.applyPostHandle(processedRequest, response, mv):最終會呼叫HandlerInterceptor的postHandle方法
具體實現是在HandlerExecutionChain中實現如下,就是獲取所有的攔截器並呼叫其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);//分別呼叫攔截器的postHandle方法
}
}
}
triggerAfterCompletion(processedRequest, response, mappedHandler, ex):最終會呼叫HandlerInterceptor的afterCompletion 方法
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err):最終會呼叫HandlerInterceptor的afterCompletion 方法
private void triggerAfterCompletionWithError(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, Error error) throws Exception {
ServletException ex = new NestedServletException("Handler processing failed", error);
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, ex);
}
throw ex;
}
private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, ex);
}
throw ex;
}
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);//呼叫攔截器的afterCompletion方法
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
通過以上程式碼分析我們可以看到HandlerInterceptor攔截器的最終呼叫實現是在DispatcherServlet的doDispatch方法中,並且SpringMVC提供了HandlerExecutionChain來幫助我們執行所有配置的HandlerInterceptor攔截器,並分別呼叫HandlerInterceptor所提供的方法。