1. 程式人生 > 其它 >責任鏈模式-以SpringMVC中DispatcherServlet的HandlerExecutionChain為例

責任鏈模式-以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