本地存根的工作方式與 AOP 的 around advice 類似,而本地偽裝的工作方式等同於 AOP 中的 after-throwing advice,也就是說,只有當遠程調用發生 exception 的時候才會執行本地偽裝。本地存根和本地偽裝的工作流程如下圖所示:

- 服務消費者發起調用
- 如果服務消費者端存在本地存根 Stub 的話,會先執行本地存根
- 本地存根 Stub 持有遠程服務的 Proxy 對象,Stub 在執行的時候,會先執行自己的邏輯 (before),然后通過 Proxy 發起遠程調用,最后在返回過程之前也會執行自己的邏輯 (after-returning)
- 如果遠程服務的 Proxy 對象在執行過程中拋出了 exception,會執行服務消費端的本地偽裝 Mock 的邏輯 (after-throwing),返回容錯數據,從而達到服務降級的目的
一、本地存根 Stub
public class DemoServiceStub implements DemoService { // #1 private final DemoService demoService; public DemoServiceStub(DemoService demoService) { // #2 this.demoService = demoService; } @Override public String sayHello(String name) { // #3 System.out.println("before execute remote service, parameter: " + name); // #4 try { String result = demoService.sayHello(name); // #5 System.out.println("after execute remote service, result: " + result); // #6 return result; } catch (Exception e) { System.out.println("fail to execute service"); // #7 return null; } } }
DemoServiceStub 運行在客戶端,要使用本地存根的話,還需要在 .xml 中配置屬性 stub。可以簡單的通過指定 stub="true" 來告訴 Dubbo 框架使用本地存根,這個時候,本地存根的包名需要和服務接口的包名一致,類名必須在服務接口的類名后加上 Stub 的后綴。例如,當服務接口名是 com.alibaba.dubbo.demo.DemoService 時,本地存根的全類名應該是com.alibaba.dubbo.demo.DemoServiceStub。
<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" stub="true"> <dubbo:method name="sayHello" retries="0"></dubbo:method> </dubbo:reference>
如果不希望使用默認的命名規則,也可以直接通過 mock 屬性來指定本地偽裝的全類名
<dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService" stub="com.alibaba.dubbo.demo.consumer.DemoServiceStub"> <dubbo:method name="sayHello" retries="0"></dubbo:method> </dubbo:reference>
通過提供一個本地偽裝的類,可以最大限度的控制出錯之后的容錯邏輯。有的時候,業務上並不需要這樣靈活的機制,只有返回一個默認值的訴求,這個時候提供一個完整的本地偽裝的實現就顯得有點重了。或者線上出錯的時候,應用並沒有打包本地偽裝,需要通過推送規則的方式臨時對服務降級。Dubbo 框架為上面的這兩種訴求都提供了快捷方式,幫助用戶快速配置服務降級。