淺談springMVC中的設計模式(1)——責任鏈模式


最近終於閑了下來,准備自己記錄些東西。網上關於springMVC的資料很多,但關於設計模式的還有限,我就想把springMVC源碼中的設計模式抽出來做成一個系列,簡單的談一下其中的實現原理,作為一種學習分享,以后有更深的感悟也會更新。
先從一張圖對整個springMVC的運作流程有一個大致的了解,圖片侵刪。


HandlerExecutionChain
其中我們可以看到,在springMVC中,DispatcherServlet這個核心類中使用到了HandlerExecutionChain這個類,他就是責任鏈模式實行的具體類。在DispatcherServlet的doDispatch這個方法中,我們可以看到它貫穿了整個請求dispatch的流程:

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 {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                // 獲取該請求的handler,每個handler實為HandlerExecutionChain,它為一個處理鏈,負責處理整個請求
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                // 責任鏈執行預處理方法,實則是將請求交給注冊的請求攔截器執行
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                // 實際的執行邏輯的部分,也就是你加了@RequestMapping注解的方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                applyDefaultViewName(processedRequest, mv);
                // 責任鏈執行后處理方法,實則是將請求交給注冊的請求攔截器執行
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            // 處理返回的結果,觸發責任鏈上注冊的攔截器的AfterCompletion方法,其中也用到了HandlerExecutionChain注冊的handler來處理錯誤結果
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            // 觸發責任鏈上注冊的攔截器的AfterCompletion方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

從上面的代碼中我們可以看到,HandlerExecutionChain主要負責請求的攔截器的執行和請求的處理,但是他本身不處理請求,只是將請求分配給在鏈上注冊的處理器執行,這是一種責任鏈的實現方式,減少了責任鏈本身與處理邏輯之間的耦合的同時,規范了整個處理請求的流程,下面我們看一下上面代碼中涉及到的方法在HandlerExecutionChain類中對應的代碼。

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;
    }
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);
            }
        }
    }
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);
                }
                catch (Throwable ex2) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                }
            }
        }
    }

代碼很容易理解,這里不詳細說明。需要注意的是,HandlerExecutionChain維護了HandlerInterceptor(攔截器)的集合,可以向其中注冊相應的HandlerInterceptor。

總結
個人的理解,責任鏈模式可以很好的將原本耦合的順序過程處理的代碼和邏輯,解耦成執行的順序邏輯,和一個個相對應的處理器(責任人),對應的責任鏈只需要關心責任處理的順序,而不需要關心具體的處理邏輯,將這些邏輯交給注冊的責任人去處理。從springMVC的源碼中,我們可以看到這一設計模式的應用,將原本復雜的請求處理邏輯表現的清楚明白。
————————————————
版權聲明:本文為CSDN博主「春天寫下一個bug」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ljw761123096/java/article/details/79591133


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM