《分佈式服務框架Dubbo》一、Dubbo原理和應用

一、dubbo的架構思路

1.1 dubbo框架設計

dubbo官網的架構設計提供了一張整體的框架圖,10個層級看起來挺嚇人的。但是其核心總結起來就是:Microkernel + Plugin(微內核+插件)

微內核+插件機制

 

官網介紹的架構設計思想是兩點:

  • 採用 URL 作爲配置信息的統一格式,所有擴展點都通過傳遞 URL 攜帶配置信息;
  • 採用 Microkernel + Plugin 模式,Microkernel 只負責組裝 Plugin,Dubbo 自身的功能也是通過擴展點實現的,也就是 Dubbo 的所有功能點都可被用戶自定義擴展所替換。

對於第一點比較容易理解,因爲是分佈式環境,各系統之間的參數傳遞基於URL來攜帶配置信息,所有的參數都封裝成 Dubbo 自定義的 URL 對象進行傳遞。URL 對象主要包括以下屬性:

 

String protocol
String host
int port
String path
Map<String, String> parameters

第二點:系統裏抽象的各個模塊,往往有很多不同的實現方案,好的設計來說:模塊之間基於接口編程,模塊之間不對實現類進行硬編碼。一旦代碼裏涉及具體的實現類,就違反了可拔插的原則,如果需要替換一種實現,就需要修改代碼,例如:

 

if(參數=="dubbo"){ 
    return new DubboProtocol(); }
else if(參數 == "rmi"){ 
    return new RMIProtocol();
 }

SPI的解決方案就呼之欲出了,一個接口對應有多個實現類的時候該怎樣指定麼?如果採用上述設計是很糟糕的,用if else來寫死自己的服務發現,如果新增一種協議則還需要去修改代碼,針對此類問題Java本身提供了spi機制,可以做到服務發現和動態擴展,但是弊端就是一初始化就把所有實現類給加載進去,dubbo改進了spi並重新命名爲ExtensionLoader(擴展點機制),按照用戶配置來指定加載模塊,只需要約定一下路徑即可:

 

private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

這部分源碼可以考察知識點非常多,對使用者來說是透明的,而精華卻良多,尤其結合java-spi,jvm以及spring等多方面對比、借鑑,因此理論上可以好好掌握,當然最好的學習方式就是按照極簡的思路來實現一個簡版RPC工具。

1.2dubbo原理、與Spring融合

dubbo是一個分佈式服務框架,致力於提供高性能和透明化的RPC遠程服務調用方案,以及SOA服務治理方案。既然是分佈式那就意味着:一個業務分拆多個子業務,部署在不同的服務器上,既然各服務是部署在不同的服務器上,那服務間的調用就是要通過網絡通信。既然涉及到了網絡通信,那麼服務消費者調用服務之前,都要寫各種網絡請求,編解碼之類的相關代碼,明顯是很不友好的.dubbo所說的透明,就是指,讓調用者對網絡請求,編解碼之類的細節透明,讓我們像調用本地服務一樣調用遠程服務,甚至感覺不到自己在調用遠程服務。

 

public class ProxyFactory implements InvocationHandler {
    private Class interfaceClass;
    public ProxyFactory(Class interfaceClass) {
        this.interfaceClass = interfaceClass;
    }
    //返回代理對象,此處用泛型爲了調用時不用強轉,用Object需要強轉
    public <T> T getProxyObject(){
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(),//類加載器
                new Class[]{interfaceClass},//爲哪些接口做代理(攔截哪些方法)
                this);//(把這些方法攔截到哪處理)
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method);
        System.out.println("進行編碼");
        System.out.println("發送網絡請求");
        System.out.println("將網絡請求結果進行解碼並返回");
        return null;
    }
}

項目引入dubbo的方法推薦用XML配置的方式引入,即便是老項目拆分改造,只要是Spring工程,這個都是比較好做的,可以想象自己如果開發一箇中間件服務,如果把服務嵌入spring容器當中呢?作爲高級開發人員這個也是一個進階的既能項。XML 配置方式是基於 Spring 的 Schema 和 XML 擴展機制實現的。通過該機制,我們可以編寫自己的 Schema,並根據自定義的 Schema 自定義標籤來配置 Bean。

使用 Spring 的 XML 擴展機制有以下幾個步驟:

  • 定義 Schema(編寫 .xsd 文件)
  • 定義 JavaBean
  • 編寫 NamespaceHandler 和 BeanDefinitionParser 完成 Schema 解析
  • 編寫 spring.handlers 和 spring.schemas 文件串聯解析部件
  • 在 XML 文件中應用配置

最好的學習效果是可以自己按照模板來一樣畫瓢來創作一個類似的xml配置。可參考《dubbo源碼解析-簡單原理、與spring融合》

1.3 服務發佈

服務的發佈總共做了以下幾件事,這個也可以從日誌log上看出來:

  • 暴露本地服務
  • 暴露遠程服務
  • 啓動netty
  • 連接zookeeper
  • 到zookeeper註冊
  • 監聽zookeeper

貼出一張官方文檔的服務發佈圖

 

服務發佈

首先 ServiceConfig 類拿到對外提供服務的實際類 ref(如:HelloWorldImpl),然後通過 ProxyFactory 類的 getInvoker方法使用 ref 生成一個 AbstractProxyInvoker 實例,到這一步就完成具體服務到 Invoker 的轉化。接下來就是 Invoker 轉換到 Exporter 的過程。Dubbo 處理服務暴露的關鍵就在 Invoker 轉換到 Exporter 的過程,上圖中的紅色部分。
Dubbo 的實現
Dubbo 協議的 Invoker 轉爲 Exporter 發生在 DubboProtocol 類的 export 方法,它主要是打開 socket 偵聽服務,並接收客戶端發來的各種請求,通訊細節由 Dubbo 自己實現。

上面摘抄了官方文檔(具體鏈接請戳),可能還是有點抽象,實際上從代碼層面進行分析:
此處就是將本地的需要暴漏的方法以url形式作爲參數傳入 exportLocal()方法,url之前已經提到過包含了ip地址、端口、接口以及配置信息等。

關鍵步驟1-本地暴露

這時會執行到一個接口方法getInvoker(),這是一個註解了@Adaptive的方法,該方法的具體實現類是運行中生成動態編譯的Adaptive類,把java編譯出來的動態類貼出來debug如下,恍然大悟,原來他就是幾個if判斷,來告訴程序我這個url參數配置的是哪種協議,我現在就動態的去調用這個擴展點服務(dubbo-spi),動態編譯的好處就是不用將代碼寫死,在協議會擴展的情況下,我根據你配置的協議來動態的生成我的extensionLoader,再來加載我所需要的Invoker。

關鍵步驟2-getInvoker()方法

上圖引用的是本地服務的暴露執行,若是遠程服務的暴露,arg2參數的開頭則會是registry://192.168.0.1:2181/com.alibaba.dubbo.** / **。從exporter對象裏包含的invoker屬性可以看出,invoker包含的攜帶ip、端口、接口以及配置信息的url。

關鍵步驟3-invoker信息

 

現在開始進入到遠程服務暴露的過程,一般來說這部分是應用和考察最多的點,通過配置的協議將服務暴露給外部調用。dubbo所支持的協議有多重,默認推薦dubbo協議,於是在動態代理的時候會生成Protocol$Adpative代理類,該代理類實現了RPC 協議接口,再通過擴展機制將服務加載進來。

關鍵步驟4-Protocol$Adpative代理類

加載了實現類後方法會順着調用鏈路進入到dubbo協議中的export()方法中來,可以再DubboProtocol類中設置斷點觀察方法執行,此處完成了一個綁定,將暴露的接口+DubboExporter進行關聯放入map中緩存。

關鍵步驟5-DubboProtocol

後面的步驟不再一一展開來講,越來越貼近底層和網絡通信,我們在調用dubbo接口的時候dubbo都爲了我們做了這樣的工作,但是對開發人員來說都是透明無感知的:

  • exchange 信息交換層。封裝請求響應模式,同步轉異步,以 Request, Response 爲中心。
  • transport 網絡傳輸層:抽象 mina 和 netty 爲統一接口,以 Message 爲中心。
  • serialize 數據序列化層:可複用的一些工具,擴展接口爲 Serialization, ObjectInput, ObjectOutput, ThreadPool

這裏引用一張肥朝博客的總結圖,來總結服務暴露所幹的事情:
首先是通過動態代理店的方式將暴露的接口組裝成url形式的invoker,然後再根據url的配置信息來指定傳輸協議、交換方式、序列化方式等等,由於dubbo採用了自定義的SPI擴展,各層之間都是相互獨立的,只有在調用的時候才知道所調用的具體擴展實現,這裏還是以jdk或者javasisit的方式來動態代理實現。

服務暴露流程

1.4 服務引用

首先 ReferenceConfig 類的init方法調用 Protocol 的 refer方法生成 Invoker 實例(如上圖中的紅色部分),這是服務消費的關鍵。接下來把 Invoker 轉換爲客戶端需要的接口(如:HelloWorld)。關於每種協議如 RMI/Dubbo/Web service 等它們在調用 refer 方法生成Invoker 實例的細節和上一章節所描述的類似。

服務應用流程

上述圖和文字是摘自官方文檔的原話(地址在這裏),總結來說就是幹了兩件事情:1、將spring的schemas標籤信息轉換bean,然後通過這個bean的信息,連接、訂閱zookeeper節點信息創建一個invoker。2、將invoker的信息創建一個動態代理對象。貼一張服務應用的時序圖:

服務引用時序

這裏又一次出現了Invoker,這個抽象的概念真是無處不在呀,dubbo中最重要的兩種 Invoker:服務提供 Invoker 和服務消費 InvokerInvoker從類的設計信息上是封裝了 Provider和Consumer地址及 Service 接口信息,我們在自己的子系統調用遠程接口的時候,會像調用自己的方法一樣,比如在消費端這裏用註解@Autowirted自動注入一個遠程接口進來,這個遠程接口就是上圖中服務消費端的 proxy,但是遠程接口是需要網絡通信、編碼解碼等等一系列工作的,要封裝這個通信細節,讓用戶像以本地調用方式調用遠程服務,就必須使用代理,然後說到動態代理,用戶代碼通過這個 proxy 調用其對應的 Invoker ,而該 Invoker 實現了真正的遠程服務調用。

image.png

二、Dubbo實戰應用

實戰應用主要是從應用層面講引入dubbo框架後如何做一些關鍵配置

2.1 Dubbo 支持四種配置方式:

XML 配置:基於 Spring 的 Schema 和 XML 擴展機制實現(推薦)
屬性配置:加載 classpath 根目錄下的 dubbo.properties
API 配置:通過硬編碼方式配置(不推薦使用,可學習加深源碼理解)
註解配置:通過註解方式配置(Dubbo-2.5.7及以上版本支持,不推薦使用)

2.2 集羣容錯

在集羣調用失敗時,Dubbo 提供了多種容錯方案,缺省爲 failover 重試。

集羣容錯

  • Invoker 是 Provider 的一個可調用 Service 的抽象,Invoker 封裝了 Provider 地址及 Service 接口信息
  • Directory 代表多個 Invoker,可以把它看成 List<Invoker> ,但與 List 不同的是,它的值可能是動態變化的,比如註冊中心推送變更
  • Cluster 將 Directory 中的多個 Invoker 僞裝成一個 Invoker,對上層透明,僞裝過程包含了容錯邏輯,調用失敗後,重試另一個
  • Router 負責從多個 Invoker 中按路由規則選出子集,比如讀寫分離,應用隔離等
  • LoadBalance 負責從多個 Invoker 中選出具體的一個用於本次調用,選的過程包含了負載均衡算法,調用失敗後,需要重選。

集羣調用的配置可從如下列表中選擇:

 

<dubbo:service cluster="failsafe" />
<!-- 或者 -->
<dubbo:reference cluster="failsafe" />
集羣模式 說明
Failfast Cluster 快速失敗,只發起一次調用,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
Failsafe Cluster 失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
Failback Cluster 失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於消息通知操作。
Forking Cluster 並行調用多個服務器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks="2" 來設置最大並行數。
Broadcast Cluster 廣播調用所有提供者,逐個調用,任意一臺報錯則報錯 [2]。通常用於通知所有提供者更新緩存或日誌等本地資源信息。

2.3 負載均衡

Random LoadBalance

  • 隨機,按權重設置隨機概率。
  • 在一個截面上碰撞的概率高,但調用量越大分佈越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者權重。

RoundRobin LoadBalance

  • 輪詢,按公約後的權重設置輪詢比率。
  • 存在慢的提供者累積請求的問題,比如:第二臺機器很慢,但沒掛,當請求調到第二臺時就卡在那,久而久之,所有請求都卡在調到第二臺上。

LeastActive LoadBalance

  • 最少活躍調用數,相同活躍數的隨機,活躍數指調用前後計數差。
  • 使慢的提供者收到更少請求,因爲越慢的提供者的調用前後計數差會越大。

ConsistentHash LoadBalance

  • 一致性 Hash,相同參數的請求總是發到同一提供者。
  • 當某一臺提供者掛時,原本發往該提供者的請求,基於虛擬節點,平攤到其它提供者,不會引起劇烈變動。
  • 算法參見:http://en.wikipedia.org/wiki/Consistent_hashing
  • 缺省只對第一個參數 Hash,如果要修改,請配置 <dubbo:parameter key="hash.arguments" value="0,1" />
  • 缺省用 160 份虛擬節點,如果要修改,請配置 <dubbo:parameter key="hash.nodes" value="320" />

 

<!--服務端服務級別-->
<dubbo:service interface="..." loadbalance="roundrobin" />

<!--客戶端服務級別-->
<dubbo:reference interface="..." loadbalance="roundrobin" />

<!--服務端方法級別-->
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>

<!--客戶端方法級別-->
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

三、dubbo面經

SPI

1、你是否瞭解SPI,講一講什麼是SPI,爲什麼要使用SPI?
SPI具體約定:當服務的提供者,提供了服務接口的一種實現之後,在jar包的META-INF/services/目錄裏同時創建一個以服務接口命名的文件。該文件裏就是實現該服務接口的具體實現類。而當外部程序裝配這個模塊的時候,就能通過該jar包META-INF/services/裏的配置文件找到具體的實現類名,並裝載實例化,完成模塊的注入(從使用層面來說,就是運行時,動態給接口添加實現類)。 基於這樣一個約定就能很好的找到服務接口的實現類,而不需要再代碼裏制定(不需要在代碼裏寫死)。

這樣做的好處:java設計出SPI目的是爲了實現在模塊裝配的時候能不在程序裏動態指明,這就需要一種服務發現機制。這樣程序運行的時候,該機制就會爲某個接口尋找服務的實現,有點類似IOC的思想,就是將裝配的控制權移到程序之外,在模塊化設計中這個機制尤其重要。例如,JDBC驅動,可以加載MySQL、Oracle、或者SQL Server等,目前有不少框架用它來做服務的擴張發現。回答這個問題可以延伸一下和API的對比,API是將方法封裝起來給調用者使用的,SPI是給擴展者使用的。

2、對類加載機制瞭解嗎,說一下什麼是雙親委託模式,他有什麼弊端,這個弊端有沒有什麼我們熟悉的案例,解決這個弊端的原理又是怎麼樣的?
擴展延生的一道題。

3、Dubbo的SPI和JDK的SPI有區別嗎?有的話,究竟有什麼區別?
Dubbo 的擴展點加載是基於JDK 標準的 SPI 擴展點發現機制增強而來的,Dubbo 改進了 JDK 標準的 SPI 的以下問題:

  • JDK 標準的 SPI 會一次性實例化擴展點所有實現,如果有擴展實現初始化很耗時,但如果沒用上也加載,會很浪費資源。
  • 增加了對擴展點 IoC 和 AOP 的支持,一個擴展點可以直接 setter 注入其它擴展點。

上文已提供。另外在博客中也單獨對此寫了一篇《Dubbo內核之SPI機制》《跟我學Dubbo系列之Java SPI機制簡介》

4、Dubbo中SPI也增加了IoC,先講講Spring的IoC,然後再講講Dubbo裏面又是怎麼做的
5、Dubbo中SPI也增加了AOP,那你講講這用到了什麼設計模式,Dubbo又是如何做的.

Dubbo原理

1、Dubbo角色和設計是怎麼樣的,原理是怎麼樣的?請簡單談談?

Dubbo角色和設計

 

2、有沒有考慮過自己實現一個類似dubbo的RPC框架,如果有,請問你會如果着手實現?(面試高頻題,區分度高)
可從兩個方面去入手,考慮接口擴展性,改造JDK的SPI機制來實現自己的擴展SPI機制。另外就是從動態代理入手,從網絡通信、編碼解碼這些步驟以動態代理的方式植入遠程調用方法中,實現透明化的調用。

3、用過mybatis是否知道Mapper接口的原理嗎?(如果回答得不錯,並且提到動態代理這個關鍵詞會繼續往下問,那這個動態代理又是如何通過依賴注入到Mapper接口的呢?)

4、服務發佈過程中做了哪些事?
暴露本地服務、暴露遠程服務、啓動netty、連接zookeeper、到zookeeper註冊、監聽zookeeper

5、dubbo都有哪些協議,他們之間有什麼特點,缺省值是什麼?
dubbo支持多種協議,默認使用的是dubbo協議,具體介紹官方文檔寫得很清楚,傳送地址:相關協議介紹,重點是掌握好推薦dubbo協議。Dubbo 缺省協議採用單一長連接和 NIO 異步通訊,適合於小數據量大併發的服務調用,以及服務消費者機器數遠大於服務提供者機器數的情況。

6、什麼是本地暴露和遠程暴露,他們的區別?
在dubbo中我們一個服務可能既是Provider,又是Consumer,因此就存在他自己調用自己服務的情況,如果再通過網絡去訪問,那自然是捨近求遠,因此他是有本地暴露服務的這個設計.從這裏我們就知道這個兩者的區別

  • 本地暴露是暴露在JVM中,不需要網絡通信.
  • 遠程暴露是將ip,端口等信息暴露給遠程客戶端,調用時需要網絡通信.

7、服務暴露中遠程暴露的總體過程,畫圖和文字方式說明
詳見上述說明

zookeeper

1、一般選擇什麼註冊中心,還有別的選擇嗎?
zk爲默認推薦,其餘還有Multicast、redis、Simple等註冊中心。

2、dubbo中zookeeper做註冊中心,如果註冊中心集羣都掛掉,那發佈者和訂閱者還能通信嗎?(面試高頻題)
zookeeper的信息會緩存到服務器本地作爲一個cache緩存文件,並且轉換成properties對象方便使用,每次調用時,按照本地存儲的地址進行調用,但是無法從註冊中心去同步最新的服務列表,短期的註冊中心掛掉是不要緊的,但一定要儘快修復。所以掛掉是不要緊的,但前提是你沒有增加新的服務,如果你要調用新的服務,則是不能辦到的。

3、項目中有使用過多線程嗎?有的話講講你在哪裏用到了多線程?(面試高頻題)
以dubbo爲例,這裏的做法是:建立線程池,定時的檢測並連接註冊中心,如果失敗了就重連,其實也就是一個定時任務執行器。可能做了兩三年java還沒真正在項目中開啓過線程,問到這個問題時菊花一緊,但是定時任務執行器這種需求在項目中還是很常見的,比如失敗重連、輪詢執行任務等等,可以參考這個例子,把你們的定時任務場景和這裏的多線程用法套在一起。

dubbo檢測zk鏈接

 

4、zookeeper的java客戶端你使用過哪些?
zookeeper是支持ZkClient和Curator兩種,關於zk的使用場景,除了以dubbo作爲註冊中心以外,zk在分佈式環境作爲協調服務器有許多應用場景,可以嘗試用java來調用zk服務做一些協調服務,如負載均衡、數據訂閱與發佈等等。SnailClimb寫了一篇優秀的博客《可能是全網把ZK概念講的最清楚的一篇文章》

zookeeper知識點一覽圖

 

5、服務提供者能實現失效踢出是什麼原理(高頻題)
在分佈式系統中,我們常常需要知道某個機器是否可用,傳統的開發中,可以通過Ping某個主機來實現,Ping得通說明對方是可用的,相反是不可用的,ZK 中我們讓所有的機器都註冊一個臨時節點,我們判斷一個機器是否可用,我們只需要判斷這個節點在ZK中是否存在就可以了,不需要直接去連接需要檢查的機器,降低系統的複雜度。

6、zookeeper的有哪些節點,他們有什麼區別?講一下應用場景
zookeeper中節點是有生命週期的.具體的生命週期取決於節點的類型.節點主要分爲持久節點(Persistent)和臨時節點(Ephemeral),但是更詳細的話還可以加上時序節點(Sequential),創建節點中往往組合使用,因此也就是4種:持久節點、持久順序節點、臨時節點、臨時順序節點。

  • 所謂持久節點,是指在節點創建後,就一直存在,直到有刪除操作來主動清除這個節點,也就是說不會因爲創建該節點的客戶端會話失效而消失。
  • 臨時節點的生命週期和客戶端會話綁定,也就是說,如果客戶端會話失效,那麼這個節點就會自動被清除掉。

7、在dubbo中,什麼時候更新本地的zookeeper信息緩存文件?訂閱zookeeper信息的整體過程是怎麼樣的?
dubbo向zk發送了訂閱請求以後,會去監聽zk的回調,(如果zk有回調就回去調用notify方法),接着會去創建接口配置信息的持久化節點,同時dubbo也設置了對該節點的監聽,zk節點如果發生了變化那麼會觸發回調方法,去更新zk信息的緩存文件,同時註冊服務在調用的時候會去對比最新的配置信息節點,有差別的話會以最新信息爲準重新暴露。《dubbo源碼解析-zookeeper訂閱》

zk訂閱流程

服務引用
1、描述一下dubbo服務引用的過程,原理
上文已提供。

2、既然你提到了dubbo的服務引用中封裝通信細節是用到了動態代理,那請問創建動態代理常用的方式有哪些,他們又有什麼區別?dubbo中用的是哪一種?(高頻題)
jdk、cglib還有javasisit,JDK的動態代理代理的對象必須要實現一個接口,而針對於沒有接口的類,則可用CGLIB。要明白兩者區別必須要瞭解原理,明白了原理自然一通百通,CGLIB其原理也很簡單,對指定的目標類生成一個子類,並覆蓋其中方法實現增強,但由於採用的是繼承,所以不能對final修飾的類進行代理。除了以上兩種大家都很熟悉的方式外,其實還有一種方式,就是javassist生成字節碼來實現代理(dubbo多處用到了javassist)。

集羣容錯
1、dubbo提供了集中集羣容錯模式?
2、談談dubbo中的負載均衡算法及特點?最小活躍數算法中是如何統計活躍數的?簡單談談一致性哈希算法
這部分可以多結合官方文檔進行學習,而且涉及到了負載均衡的多個重要算法,也是高頻的考察熱點。

3、怎麼通過dubbo實現服務降級的,降級的方式有哪些,又有什麼區別?
當網站處於高峯期時,併發量大,服務能力有限,那麼我們只能暫時屏蔽邊緣業務,這裏面就要採用服務降級策略了。首先dubbo中的服務降級分成兩個:屏蔽(mock=force)、容錯(mock=fail)。

  • mock=force:return+null 表示消費方對該服務的方法調用都直接返回 null 值,不發起遠程調用。用來屏蔽不重要服務不可用時對調用方的影響。
  • mock=fail:return+null 表示消費方對該服務的方法調用在失敗後,再返回 null 值,不拋異常。用來容忍不重要服務不穩定時對調用方的影響。

要生效需要在dubbo後臺進行配置的修改:

 

服務降級策略

4、dubbo監控平臺能夠動態改變接口的一些設置,其原理是怎樣的?
改變註冊在zookeeper上的節點信息,從而zookeeper通知重新生成invoker(這些具體細節在zookeeper創建節點,zookeeper連接,zookeeper訂閱中都詳細講了,這裏不再重複)。

學習框架三部曲:

  • 掌握基本使用
  • 看過源碼,知道其中原理
  • 臨摹源碼,自己仿寫一個簡易的框架

臨摹源碼的這個過程,也需要分爲三個過程,分別是入門版(用最簡單的代碼表達出框架原理),進階版(加入設計模式等思想,在入門版的基礎上優化代碼),高級版(和框架代碼基本一致)。


《dubbo源碼解析》
《cyfonly-DUBBO源碼系列文章》



作者:千淘萬漉
鏈接:https://www.jianshu.com/p/292fcdcfe41e
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章