dubbo 暴露服務 和引用服務
1. Dubbo概述
Dubbo是阿里巴巴開源出來的一個分散式服務框架,致力於提供高效能和透明化的RPC遠端服務呼叫方案,以及作為SOA服務治理的方案。它的核心功能包括:
#remoting:遠端通訊基礎,提供對多種NIO框架抽象封裝,包括“同步轉非同步”和“請求-響應”模式的資訊交換方式。
#Cluster: 服務框架核心,提供基於介面方法的遠端過程呼叫,包括多協議支援,並提供軟負載均衡和容錯機制的叢集支援。
#registry: 服務註冊中心,使服務消費方能動態的查詢服務提供方,使地址透明,使服務提供方可以平滑增加或減少機器。
這裡我們只是補充一下從原始碼具體實現角度來看的某些細節方面,包括Invoker、ExtensionLoader等方面。任何官方已經介紹過的細節,我們不做畫蛇添足,官方文件已經足夠詳實了,這篇文件的定位是補充實現的相關細節,是基於我在往Dubbo新增web service協議過程中,所碰到過的一些困難。
2. 服務提供者暴露一個服務的詳細過程
上圖是服務提供者暴露服務的主過程:
首先ServiceConfig類拿到對外提供服務的實際類ref(如:HelloWorldImpl),然後通過ProxyFactory類的getInvoker方法使用ref生成一個AbstractProxyInvoker例項,到這一步就完成具體服務到Invoker的轉化。接下來就是Invoker轉換到Exporter的過程。
Dubbo處理服務暴露的關鍵就在Invoker轉換到Exporter的過程(如上圖中的紅色部分),下面我們以Dubbo和RMI這兩種典型協議的實現來進行說明:
#Dubbo的實現
Dubbo協議的Invoker轉為Exporter發生在DubboProtocol類的export方法,它主要是開啟socket偵聽服務,並接收客戶端發來的各種請求,通訊細節由Dubbo自己實現。
#RMI的實現
RMI協議的Invoker轉為Exporter發生在RmiProtocol類的export方法,它通過Spring或Dubbo或JDK來實現RMI服務,通訊細節這一塊由JDK底層來實現,這就省了不少工作量。
3. 服務消費者消費一個服務的詳細過程
上圖是服務消費的主過程:
首先ReferenceConfig類的init方法呼叫Protocol的refer方法生成Invoker例項(如上圖中的紅色部分)
關於每種協議如RMI/Dubbo/Web service等它們在呼叫refer方法生成Invoker例項的細節和上一章節所描述的類似。
4. 滿眼都是Invoker
由於Invoker是Dubbo領域模型中非常重要的一個概念,很多設計思路都是向它靠攏。這就使得Invoker滲透在整個實現程式碼裡,對於剛開始接觸Dubbo的人,確實容易給搞混了。
下面我們用一個精簡的圖來說明最重要的兩種Invoker:服務提供Invoker和服務消費Invoker:
#服務消費者程式碼
public class DemoClientAction {
private DemoService demoService;
public void setDemoService(DemoService demoService) {
this.demoService = demoService;
}
public void start() {
String hello = demoService.sayHello("world" + i);
}
} 上面程式碼中的’DemoService’就是上圖中服務消費端的proxy,使用者程式碼通過這個proxy呼叫其對應的Invoker(DubboInvoker、 HessianRpcInvoker、 InjvmInvoker、 RmiInvoker、 WebServiceInvoker中的任何一個),而該Invoker實現了真正的遠端服務呼叫。#服務提供者程式碼
public class DemoServiceImpl
implements DemoService
{
public String sayHello(String name) throws RemoteException
{
return "Hello " + name;
}
}
上面這個類會被封裝成為一個AbstractProxyInvoker例項,並新生成一個Exporter例項。這樣當網路通訊層收到一個請求後,會找到對應的Exporter例項,並呼叫它所對應的AbstractProxyInvoker例項,從而真正呼叫了服務提供者的程式碼。
Dubbo裡還有一些其他的Invoker類,但上面兩種是最重要的。
5. ExtensionLoader的完整分析
ExtensionLoader是Dubbo中一個非常重要的類,剛接觸Dubbo原始碼的人看這個類的時候也多少會有點困惑,這個類非常重要,它就像是廚房裡的“大廚”,按照使用者的隨時需要把各種“食材”烹調出來。
我們結合具體程式碼詳細說一下ExtensionLoader的實現,下面是ServiceConfig類裡的一行程式碼:
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
上面程式碼的程式流程圖如下所示(假定是第一次執行這行程式碼):
在這個過程中最重要的兩個方法是getExtensionClasses和createAdaptiveExtensionClass(圖中紅色部分),下面詳細對這兩個方法進行分析:
#getExtensionClasses
這個方法主要讀取META-INF/services/目錄下對應檔案內容,在本示例程式碼中,是讀取META-INF/services/com.alibaba.dubbo.rpc.Protocol檔案中的內容,具體內容如下:
com.alibaba.dubbo.registry.support.RegistryProtocol
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
它分析該檔案中的每一行(每一行對應一個類),分析這些類,如果發現有哪個類的Annotation是@Adaptive,則找到對應的AdaptiveClass了,但由於Protocol檔案裡沒有哪個類的Annotation是@Adaptive,所以在這個例子中該方法沒找到對應的AdaptiveClass。
#createAdaptiveExtensionClass
該方法是在getExtensionClasses方法找不到AdaptiveClass的情況下被呼叫,該方法主要是通過位元組碼的方式在記憶體中新生成一個類,它具有AdaptiveClass的功能,Protocol就是通過這種方式獲得AdaptiveClass類的。
AdaptiveClass類的作用是能在執行時動態判斷具體是要呼叫哪個類的方法,更多關於AdaptiveClass的內容請參考Dubbo官方文件。