設計模式之【委派模式】+ 框架源碼分析

點讚的靚仔,你最帥哦!

源碼已收錄github 查看源碼,別忘了star哦!java

開題

初入博客圈,第一個編寫的專題定位在設計模式,前面已經完成了部分設計模式的內容,設計模式是框架架構設計的基礎,不能說懂設計模式纔會懂框架,但懂設計模式必定能夠更好的懂框架,而對設計模式深刻了解後,當工做中遇到需求或者問題的時候,甚至可以天然而然的想到用設計模式來解決。git

更重要的是,咱們學習技術是爲了提高自我,找到一份好的工做。那麼做爲面試中的高頻題目,很是有必要掌握。本文經過理論 + 實踐 + 源碼解讀的方式來詳細的結束委派模式。github

委派模式

委派模式並不複雜,和其字面含義相似,指委派者接收任務,而後將任務分配給具體作這個任務的對象。就像作項目同樣,老闆安排任務給項目經理,項目經理再將任務委託給具體作任務的人。面試

這樣咋一看和代理模式很是相似,其實能夠理解委託模式就是一種特殊的代理模式,他們的區別在於各自關注的點不一樣,代理模式一般注重代理的過程,如前置、後置、環繞等功能的加強;而委派模式不注重過程,注重任務的執行結果,就像老闆,他不關心項目經理把這件事情安排給誰完成,他關注的是最終的結果。
express

委派模式主要涉及到三種角色:委派者、工做者、任務
如上個圖例,委派者即項目經理,工做者即產品、架構師、後端,任務即要作的事情。下面經過代碼實現。後端

工做者接口設計模式

package demo.pattren.delegate;

public interface Worker {
    void doJob(Job job);
}

Job定義任務類架構

package demo.pattren.delegate;

import lombok.Data;
@Data
public class Job {
    //實際開發中的任務類確定比較複雜,屬性很是多
    private String jobName;
}

Worker的其中一個實現,大體相似。其餘就省略了,能夠在文章開頭去個人Github拉取源碼。框架

package demo.pattren.delegate;

/**
 * 開發
 */
public class Development implements Worker {
    @Override
    public void doJob(Job job) {
        System.out.println("開發人員向你拋出異常,項目延期");
        System.out.println("加班加點,開發人員完成工做");
        System.out.println("開發人員黑着眼圈,並完成" + job.getJobName());
    }
}

測試ide

package demo.pattren.delegate;

import java.util.ArrayList;
import java.util.List;
/**
 * 委派模式模擬測試測試
 */
public class DelegateTest {
    public static void main(String[] args) {
        //任務
        List<Job> project = new ArrayList<>();
        Job job1 = new Job();
        Job job2 = new Job();
        Job job3 = new Job();
        job1.setJobName("原型");
        job2.setJobName("架構");
        job3.setJobName("開發");
        project.add(job1);
        project.add(job2);
        project.add(job3);

        ProjectManager manager = new ProjectManager();
        //產品經理委派任務,對老闆來講,任務都交給項目經理,並不關心具體誰完成
        project.forEach(item -> manager.dispatch(item));
    }
}

深刻源碼解讀委派模式

一般寫代碼的時候,一般會在類名後面加上設計模式的名稱,好比JdbcTemplate就用到了模板模式, 委派模式在JDK以及框架中應用很是多,咱們用Delegate在Idea中查詢,能夠查到一大堆,幾十上百個不止。

咱們找一個比較熟悉的BeanDefinitionParserDelegate,查看該類在那些地方有使用。
關於該類的做用翻譯以下:

Stateful delegate class used to parse XML bean definitions.

Intended for use by both the main parser and any extension

解析XML配置的委託類,即真正解析XML內容的類。

能夠同時用於主解析器以及主解析器的擴展。

若是瞭解過Spring的容器初始化Bean的過程,那麼必定對BeanDefinitionReader不陌生,BeanDefinitionReader是用於讀取Bean定義的接口,最終解析配置返回BeanFefinition對象,Debug跟蹤源碼,在XML定義的Bean的解析最終是交由BeanDefinitionParserDelegate完成的,類圖結構以下。

XmlBeanDefinitionReader.registerBeanDefinitions

//解析XML並註冊爲BeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //建立reader
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    //註冊解析Bean
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

該方法核心代碼是註冊解析Bean,繼續追蹤

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
  this.readerContext = readerContext;
  //調用do方法, 
  doRegisterBeanDefinitions(doc.getDocumentElement());
}

以do開頭的都是真正幹活的方法,繼續追蹤

protected void doRegisterBeanDefinitions(Element root) {
    //保存當前結點的父委派對象,由於xml是有層級和包含關係,因此處理這裏的時候是遞歸進行的,
    //保證能夠正確解析xml到beanDefinition
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            // We cannot use Profiles.of(...) since profile expressions are not supported
            // in XML config. See SPR-12458 for details.
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                            "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }

    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
}

此時請求執行到了BeanDefinitionParserDelegate,而BeanDefinitionParserDelegate還不是真正解析的類,而是將解析的工做交由解析器處理。咱們再將類圖關係完善,整個解析處理流程以下。

至此,整個處理流程已經清晰。簡單總結。

Spring從XML解析到BeanDefinition流程以下。XmlBeanDefinitionReader爲起點,任務交由DefaultBeanDefinitionDocumentReader處理,DefaultBeanDefinitionDocumentReader經過委託類BeanDefinitionParserDelegate將解析任務委託給真正的解析器BeanDefinitionParser的實現類處理。

相關文章
相關標籤/搜索