dubbo架構
RPC呼叫鏈如下
服務消費方代理建立流程圖更多架構請參考dubbo官方開發者指南http://dubbo.apache.org/en-us/docs/dev/design.html
通過這個流程圖可以看到dubbo的呼叫鏈是非常複雜的,並且dubbo抽象了非常多的SPI介面,保證了dubbo的擴充套件性。讓dubbo是一個非常容易擴充套件的框架。
- ProxyFactory SPI介面實現Invoker和服務介面和物件的相互轉換
- Filter SPI介面實現Invoker呼叫鏈的攔截,自由的新增擴充套件邏輯
- Invoker介面實現可以實現本地以及遠端service方法的呼叫
- Cluster SPI介面可以實現從Invoker
- Directory選擇Invoker來實現失敗重試策略
- LoadBalance SPI介面可以實現從多個可用的Invoker中負載均衡策略
- Registry SPI介面可以實現URL的註冊,查詢和訂閱,取消訂閱
- Protocol SPI介面實現基於service呼叫的入參,呼叫對應網路通訊框架來建立遠端方法呼叫Invoker。
- Directory介面實現RegistryDirectory通過Registry訂閱到服務提供方的List,根據每個提供方URL呼叫Protocol實現類建立Invoker, 實現根據遠端方法呼叫資訊Invocation資訊返回Invoker List
dubbo核心介面之 Invoker物件
dubbo裡面大部分方法的入參都是Invoker物件,是dubbo裡面最核心的介面
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.Node;
/**
* Invoker. (API/SPI, Prototype, ThreadSafe)
*
* @see com.alibaba.dubbo.rpc.Protocol#refer(Class, com.alibaba.dubbo.common.URL)
* @see com.alibaba.dubbo.rpc.InvokerListener
* @see com.alibaba.dubbo.rpc.protocol.AbstractInvoker
* @author william.liangf
*/
public interface Invoker<T> extends Node {
/**
* get service interface.
*
* @return service interface.
*/
Class<T> getInterface();
/**
* invoke.
*
* @param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
}
import com.alibaba.dubbo.common.URL;
/**
* Node. (API/SPI, Prototype, ThreadSafe)
*
* @author william.liangf
*/
public interface Node {
/**
* get url.
*
* @return url.
*/
URL getUrl();
/**
* is available.
*
* @return available.
*/
boolean isAvailable();
/**
* destroy.
*/
void destroy();
}
複製程式碼
dubbo的資料匯流排URL物件描述了請求的協議型別,請求引數資料,dubbo.xml裡面的配置引數資訊都會轉化為url物件用於整個呼叫鏈來傳遞配置資訊。
dubbo客戶端註冊到註冊中心的url例項 consumer://192.168.0.1/com.dq.test.xxxService?application=sita-crm-front&category=consumers&check=false&default.check=false&dubbo=2.8.4&group=crm-web&interface=com.dq.test.xxxService&pid=733&revision=0.0.1-SNAPSHOT&side=consumer&timeout=60000×tamp=1537006745855
dubbo服務端註冊到註冊中心的url例項 dubbo://192.168.0.1:20880/xxxService?anyhost=true&application=crm-web&default.delay=-1&default.group=crm-web&default.timeout=10000&delay=-1&dubbo=2.8.4&generic=false&interface=xxxService&pid=610&revision=0.0.1-SNAPSHOT&side=provider×tamp=1537005166465
Invocation物件的實現封裝了遠端呼叫的請求資料,預設的實現是RpcInvocation類
public interface Invocation {
/**
* get method name.
*
* @serial
* @return method name.
*/
String getMethodName();
/**
* get parameter types.
*
* @serial
* @return parameter types.
*/
Class<?>[] getParameterTypes();
/**
* get arguments.
*
* @serial
* @return arguments.
*/
Object[] getArguments();
/**
* get attachments.
*
* @serial
* @return attachments.
*/
Map<String, String> getAttachments();
/**
* get attachment by key.
*
* @serial
* @return attachment value.
*/
String getAttachment(String key);
/**
* get attachment by key with default value.
*
* @serial
* @return attachment value.
*/
String getAttachment(String key, String defaultValue);
/**
* get the invoker in current context.
*
* @transient
* @return invoker.
*/
Invoker<?> getInvoker();
}
複製程式碼
dubbo核心之Protocal
@SPI("dubbo")
public interface Protocol {
/**
* 獲取預設埠,當使用者沒有配置埠時使用。
*
* @return 預設埠
*/
int getDefaultPort();
/**
* 暴露遠端服務:<br>
* 1. 協議在接收請求時,應記錄請求來源方地址資訊:RpcContext.getContext().setRemoteAddress();<br>
* 2. export()必須是冪等的,也就是暴露同一個URL的Invoker兩次,和暴露一次沒有區別。<br>
* 3. export()傳入的Invoker由框架實現並傳入,協議不需要關心。<br>
*
* @param <T> 服務的型別
* @param invoker 服務的執行體
* @return exporter 暴露服務的引用,用於取消暴露
* @throws RpcException 當暴露服務出錯時丟擲,比如埠已佔用
*/
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
/**
* 引用遠端服務:<br>
* 1. 當使用者呼叫refer()所返回的Invoker物件的invoke()方法時,協議需相應執行同URL遠端export()傳入的Invoker物件的invoke()方法。<br>
* 2. refer()返回的Invoker由協議實現,協議通常需要在此Invoker中傳送遠端請求。<br>
* 3. 當url中有設定check=false時,連線失敗不能丟擲異常,並內部自動恢復。<br>
*
* @param <T> 服務的型別
* @param type 服務的型別
* @param url 遠端服務的URL地址
* @return invoker 服務的本地代理
* @throws RpcException 當連線服務提供方失敗時丟擲
*/
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
/**
* 釋放協議:<br>
* 1. 取消該協議所有已經暴露和引用的服務。<br>
* 2. 釋放協議所佔用的所有資源,比如連線和埠。<br>
* 3. 協議在釋放後,依然能暴露和引用新的服務。<br>
*/
void destroy();
}
複製程式碼