本地存根
- 本地存根類似於Dubbo的靜態代理。
- dubbo會在客戶端生成一個代理。
- stub必須有可傳入Proxy的函數。
遠程服務後,客戶端通常只剩下接口,而實現全在服務端,但提供方有些時候想在客戶端也執行部分邏輯,比如:做ThreadLocal緩存,提前驗證參數,調用失敗後僞造容錯數據等等,此時就需要在API中帶上Stub,客戶端生成Proxy實例,會把Proxy通過構造函數傳給stub, 然後把Stub暴露給用戶,stub可以決定要不要去調Proxy。
在spring配置文件中按以下方式配置:
<dubbo:service interface="com.foo.BarService" stub="true" />
或
<dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" />
提供Stub的實現,在interface旁邊放一個Stub的實現,它實現BarService接口,並有一個傳入遠程BarService實例的構造函數。
package com.foo;
public class BarServiceStub implements BarService {
private final BarService barService;
// 構造函數傳入真正的遠程代理對象
public BarServiceStub(BarService barService){
this.barService = barService;
}
public String sayHello(String name) {
// 此代碼在客戶端執行, 你可以在客戶端做ThreadLocal本地緩存,或預先驗證參數是否合法,等等
try {
return barService.sayHello(name);
} catch (Exception e) {
// 你可以容錯,可以做任何AOP攔截事項
return "容錯數據";
}
}
}
本地僞裝
- 本地僞裝是本地存根的一個子集。
- 通常會使用本地僞裝處理服務降級。
- 建議本地僞裝在客戶端實現。
本地僞裝通常用於服務降級,比如某驗權服務,當服務提供方全部掛掉後,客戶端不拋出異常,而是通過Mock數據返回授權失敗。Mock只能捕獲RpcException 類。
在 spring 配置文件中按以下方式配置:
<dubbo:reference interface=“com.foo.BarService” mock=“true” />
或
<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
在工程中提供 Mock 實現 , 在interface旁邊放一個Mock實現,它實現BarService接口,並有一個無參構造函數。
package com.foo;
public class BarServiceMock implements BarService {
public String sayHello(String name) {
// 你可以僞造容錯數據,此方法只在出現RpcException時被執行
return "容錯數據";
}
}
如果服務的消費方經常需要 try-catch 捕獲異常,如:
Offer offer = null;
try {
offer = offerService.findOffer(offerId);
} catch (RpcException e) {
logger.error(e);
}
請考慮改爲 Mock 實現,並在 Mock 實現中 return null。如果只是想簡單的忽略異常,在 2.0.11 以上版本可用:
<dubbo:reference interface="com.foo.BarService" mock="return null" />
進階用法
return
使用return
來返回一個字符串表示的對象,作爲Mock的返回值。合法的字符串可以是:
- empty: 代表空,基本類型的默認值,或者集合類的空值
- null: null
- true: true
- false: false
- JSON 格式: 反序列化 JSON 所得到的對象
throw
使用 throw 來返回一個 Exception 對象,作爲 Mock 的返回值。
當調用出錯時,拋出一個默認的 RPCException:
<dubbo:reference interface="com.foo.BarService" mock="throw" />
當調用出錯時,拋出指定的 Exception:
<dubbo:reference interface="com.foo.BarService" mock="throw com.foo.MockException" />
force 和 fail
在 2.6.6 以上的版本,可以開始在 Spring XML 配置文件中使用 fail: 和 force:。force: 代表強制使用 Mock 行爲,在這種情況下不會走遠程調用。fail: 與默認行爲一致,只有當遠程調用發生錯誤時才使用 Mock 行爲。force: 和 fail: 都支持與 throw 或者 return 組合使用。
強制返回指定值:
<dubbo:reference interface="com.foo.BarService" mock="force:return fake" />
強制拋出指定異常:
<dubbo:reference interface="com.foo.BarService" mock="force:throw com.foo.MockException" />
在方法級別配置 Mock
Mock 可以在方法級別上指定,假定 com.foo.BarService 上有好幾個方法,我們可以單獨爲 sayHello() 方法指定 Mock 行爲。具體配置如下所示,在本例中,只要 sayHello() 被調用到時,強制返回 “fake”:
<dubbo:reference id="demoService" check="false" interface="com.foo.BarService">
<dubbo:parameter key="sayHello.mock" value="force:return fake"/>
</dubbo:reference>
隱式參數
可以通過RpcContext
上的setAttachment
和getAttachment
在這裏插入代碼片在服務消費方和提供方之間進行參數的隱式傳遞。
在服務消費方端設置隱式參數
setAttachment 設置的 KV 對,在完成下面一次遠程調用會被清空,即多次遠程調用要多次設置。
RpcContext.getContext().setAttachment("index", "1"); // 隱式傳參,後面的遠程調用都會隱式將這些參數發送到服務器端,類似cookie,用於框架集成,不建議常規業務使用
xxxService.xxx(); // 遠程調用
// ...
在服務提供方端獲取隱式參數
public class XxxServiceImpl implements XxxService {
public void xxx() {
// 獲取客戶端隱式傳入的參數,用於框架集成,不建議常規業務使用
String index = RpcContext.getContext().getAttachment("index");
}
}