責任鏈模式-以SpringMVC中DispatcherServlet的HandlerExecutionChain為例
責任鏈模式的定義:
責任鏈模式為請求建立了一個接收者物件的鏈,在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個物件不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推。
在SpringMVC中DispatcherServlet的HandlerExecutionChain也應用了這一設計模式的思路(可能並不是太典型,這個最後總結):
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 { ... // Determine handler for the current request. mappedHandler = getHandler(processedRequest);// Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); ...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); } ... }
重點看標紅的程式碼,在doDispatch方法中定義並獲取了HandlerExecutionChain的物件,然後呼叫了applyPreHandle、applyPostHandle方法。
首先看下HandlerExecutionChain的作用:
public class HandlerExecutionChain { private final Object handler; @Nullable private HandlerInterceptor[] interceptors; @Nullable private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1; ...
HandlerExecutionChain持有http請求的處理器,即程式碼中的handler物件,以及攔截器的陣列interceptors,既處理http請求的具體邏輯,又使用攔截器對http請求進行攔截,而此處對於攔截器的呼叫就應用了責任鏈模式的思路:
applyPreHandle方法:
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方法對請求進行處理,並且只有當本次preHandle處理返回true時,下一個攔截器才會進行執行preHandle方法;如果返回false,就執行triggerAfterCompletion並跳出迴圈。
總結:為什麼開頭說不是特別典型的責任鏈模式,因為此處的攔截器沒有包含對另一攔截器的引用,而是通過陣列的方式來達到類似的效果。
triggerAfterCompletion方法:
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable 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); } } } }
此處邏輯類似,只不過這裡呼叫的是攔截器的afterCompletion方法。
applyPostHandle方法:
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable 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方法。
典型責任鏈模式:
https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html