天天看點

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