點讚的靚仔,你最帥哦!
源碼已收錄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完成的,類圖結構以下。
//解析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的實現類處理。