1. 程式人生 > >SpringMVC 請求處理 - HandlerInterceptor

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所提供的方法。