源碼學習之設計模式(委託模式)

今天要說的是委派模式。java

使用起來 和代理模式有點像,在《設計模式之禪》中講到代理模式就是委派模式,對於這個觀點我不敢苟同。看了《Spring5核心原理與30個類手寫實戰》以及網上查閱資料,我總結了如下幾點:ios

  • 代理模式注重過程,而委派模式更加看重結果。生活中常有委派發生,班級大掃除的時候,班主任安排任務給班長,班長把分配給同窗們,班主任呢,他只關注打掃的乾不乾淨,至於怎麼打掃的,他不太關心。
  • 代理模式的對象自始至終都沒有發生改變,且在代理模式中代理類不能改變業務邏輯。委託偏偏相反,不只能夠實現都有的邏輯,也能夠自由的更換委託對象,就像上面的例子,老師也能夠把任務委派給衛生委員。
  • 在編程方面,代理模式更像是上下級的關係,委託則像平級關係。

    下面分析源碼加深一下理解。web

源碼分析

jdk中有一個典型的委託,衆所周知jvm在加載類是用的雙親委託模型,這又是什麼呢?一個類加載器在加載類時,先把這個請求委託給本身的父類加載器去執行,若是父類加載器還存在父類加載器,就繼續向上委託,直到頂層的啓動類加載器。若是父類加載器可以完成類加載,就成功返回,若是父類加載器沒法完成加載,那麼子加載器纔會嘗試本身去加載。從定義中能夠看到雙親加載模型一個類加載器加載類時,首先不是本身加載,而是委託給父加載器。這就和上面打掃衛生的例子很像。父加載器確定有本身的業務邏輯 ,對比下代理模式,正好印證上面的第二條。下面咱們來看看loadClass方法的源碼,此方法位於ClassLoader類裏。spring

在此類裏定義了一個雙親,用於下面的加載。編程

// The parent class loader for delegation
    // Note: VM hardcoded the offset of this field, thus all new fields
    // must be added *after* it.
    private final ClassLoader parent;
protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }

一樣在Methodl類裏咱們經常使用代理執行方法invoke()也存在相似的機制。設計模式

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

看完代碼,相信童鞋們對委託和代理區別搞清楚了吧。在spring的DispacherServlet也實現了委託,讓咱們一塊兒來看下吧。微信

委託在Spring中應用

學過spring都知道DispacherServlet是提供web的集中訪問點,分配任務去給處理器執行app

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);

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                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);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                // As of 4.3, we're processing Errors thrown from handler methods as well,
                // making them available for @ExceptionHandler methods and other scenarios.
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", 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);
                }
            }
        }
    }

DispacherServlet將任務分配給處理器,主要由jvm

  • HandlerAdapter:肯定當前請求的處理程序適配器
  • HandlerExecutionChain:肯定當前請求的處理程序。
  • cleanupMultipart():清理multipart多餘的資源。
  • HandlerMapping:將請求映射處處理器
  • ViewReslover: 解析視圖名到具體試圖實現。

從以上咱們能夠看出DispatcherServlet主要負責流程的控制。固然我分析的可能有出入,小夥伴們能夠指出來,一塊兒討論。async

好了,委託模式就到這了,童鞋們只有深刻理解委託和代理的異同點,才能在之後的學習生活中更好的使用,至少還能夠在小夥伴面前裝個逼。哈哈哈哈哈哈哈哈哈

看過個人博文都知道,個人文章會有大幅度代碼,有些人可能會質疑我。我我的認爲,學習東西須要思考,思考有個方向,文字解釋只是引導方向,閱讀了相關的代碼,並思考代碼中應用,纔能有本身的體會 ;光靠別人解釋,吃別人咀嚼過東西沒有味道,體會不到真正的意義。僅表明我的觀點,有不一樣意見能夠提出,一塊兒討論。

聲明

本文章爲做者讀書筆記及感悟,其中參考了《spring5核心原理與30個類手寫實戰》以及互聯網上的內容。若有錯誤,請評論或者私聊我,歡迎探討技術問題 。即將畢業,在準備找工做,有朋友想給我介紹的,歡迎添加微信:sllbiao。

相關文章
相關標籤/搜索