
今天詳細的分解一下Dubbo的擴展機制,實現快速入門,豐富個人簡歷,提高面試level,給自己增加一點談資,秒變面試小達人,BAT不是夢。
說真的,從零學習Dubbo,看這個系列足夠了,共10篇,歡迎持續關注,相約每天早八點。
三分鐘你將學會:
- Dubbo的自適應擴展機制
- Dubbo的SPI擴展機制
- Dubbo的自定義擴展點機制
- Dubbo的過濾器擴展機制
- Dubbo的負載均衡擴展機制;
- Dubbo的容錯機制擴展;
一、Dubbo擴展機制的概述
Dubbo是一個高性能的分布式服務框架,廣泛應用于各種規模和種類的企業級項目中。在實際應用過程中,Dubbo的核心能力是擴展機制,它可以讓Dubbo具有更強的可定制化能力,也可以讓Dubbo更好地適應各種應用場景。

Dubbo的擴展機制
Dubbo的擴展機制主要包括:自適應擴展機制、SPI擴展機制、自定義擴展點機制、過濾器擴展機制、負載均衡擴展機制和容錯機制擴展。
這些機制使得Dubbo的使用更加靈活方便,可以滿足不同需要的業務場景,也可以根據實際情況來選擇合適的擴展機制。
在Dubbo的擴展機制中,尤其需要注意自定義擴展點機制和SPI擴展機制。這些機制是Dubbo中較為重要和常用的擴展機制,充分了解這些機制可以讓應用程序更加靈活和可定制。
下圖展示了Dubbo擴展機制的調用流程:

Dubbo擴展機制
上圖中,Dubbo客戶端首先會通過ExtensionLoader加載需要使用的擴展點,ExtensionLoader會根據客戶端傳入的擴展點名和配置,創建對應的擴展點實例,并返回給客戶端,客戶端再通過返回的擴展點實例調用相應的方法。
二、Dubbo的自適應擴展機制
1、什么是自適應擴展機制
自適應擴展機制是Dubbo提供的一種機制,它可以使Dubbo框架根據實際使用情況動態地選擇不同的擴展實現,從而達到最優的效果。
?自適應擴展機制的實現方式是通過在擴展接口的代理類中,根據實際情況動態地生成對應擴展實現的代理類實例。
下圖是自適應擴展機制的詳細時序圖:

自適應擴展機制
上圖中:
- Client先調用ExtensionLoader加載擴展點,并解析配置文件;
- ExtensionLoader根據配置文件查找實現類
- 然后創建一個AdaptiveExtension的代理對象,并將該代理對象返回給Client;
- Client調用代理對象的方法時,AdaptiveExtension會根據配置使用具體的擴展點實現,并將調用轉發給具體的擴展點實現;
- 最后將結果返回給Client;
2、自適應擴展機制的使用示例
在Dubbo框架中,有一個名為Protocol的擴展接口,它有多種不同的實現方式,如dubbo、rmi、http等。在使用Dubbo時,我們可以通過@Reference注解來注入對應的擴展實現,如:
@Reference(protocol = "dubbo")
private DemoService demoService;
在上述代碼中,我們指定了使用dubbo協議的DemoService接口的擴展實現。
我們也可以通過adaptive屬性來實現自適應調用,如:
@Reference(adaptive = "true")
private Protocol protocol;
在上述代碼中,我們使用了adaptive屬性,并注入了Protocol類型的實例。這時,Dubbo框架會根據實際情況動態地生成對應實現的代理類,并返回對應的實例。
三、Dubbo的SPI擴展機制
1、什么是SPI擴展機制
Dubbo使用了JAVA的SPI(Service Provider Interface)擴展機制。SPI是JDK內置的一種服務發現機制,其具體實現方式是在資源文件META-INF/services中通過名稱為SPI接口的全限定類名創建一個文本文件,在這個文本文件中可以寫入該SPI接口的實現類全限定類名,這樣可以實現動態加載實現類的目的。
?Dubbo中的SPI擴展機制能夠在不修改核心源代碼的前提下,通過修改配置文件或者實現自定義拓展類的方式來替換或增加核心功能。
下圖描述了 Dubbo SPI 擴展機制的工作流程:

SPI 擴展機制
上圖描述了 Dubbo SPI 擴展機制的工作流程,其中:
- 用戶向 Dubbo Framework 請求獲取 ExtensionLoader,ExtensionLoader 是 Dubbo SPI 擴展機制的核心類;
- Dubbo Framework 加載 ExtensionLoader,并返回給用戶;
- 用戶調用 ExtensionLoader 的方法;
- ExtensionLoader 根據指定的 Extension 接口,通過 SPI 機制加載 Extension 實現;
- Extension 實現將被加載,ExtensionLoader 返回 Extension 實現給用戶;
2、SPI擴展機制的使用示例
首先,我們需要定義一個SPI擴展接口,讓Dubbo的擴展實現類都實現該接口。
示例代碼:
package com.example.extension;
import com.alibaba.dubbo.common.extension.SPI;
@SPI("default")
public interface PrintService {
void print(String msg);
}
在接口上添加@SPI注解,指定該擴展的默認實現類。
然后,我們需要在META-INF/services目錄下創建一個“接口全限定類名”的文件名的文件,文件中寫入我們實現的SPI擴展類的全限定類名。
比如我們需要同過實現PrintService接口來實現打印功能,那么我們在META-INF/services/目錄下創建一個名為“com.example.extension.PrintService”的文件,文件內容為:
com.example.extension.impl.ConsolePrintServiceImpl
接下來,我們就可以通過Dubbo框架自動加載通過SPI機制注冊的實現類了。
示例代碼:
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PrintService printService =
ExtensionLoader.getExtensionLoader(PrintService.class).getDefaultExtension();
printService.print("hello world!");
以上代碼中,我們使用Dubbo的擴展加載器ExtensionLoader來獲取PrintService接口的默認實現類,然后調用該實現類的print()方法即可實現打印功能。
3、Dubbo的SPI擴展機制中自定義擴展點的實現示例
在Dubbo框架中,我們可以通過自定義擴展點來增強Dubbo的功能。
自定義擴展點需要實現Dubbo提供的ExtensionFactory接口,并在META-INF/dubbo/internal/?路徑下創建一個文件名為com.alibaba.dubbo.common.extension.ExtensionFactory的文件,文件中寫入擴展點實現類的全限定類名。
示例代碼:
package com.example.extension;
import com.alibaba.dubbo.common.extension.ExtensionFactory;
public class MyExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
if (type.equals(PrintService.class)) {
return (T) new ConsolePrintServiceImpl();
}
return null;
}
}
在MyExtensionFactory中實現getExtension()方法,并根據type參數判斷獲取哪個擴展實現類。
在本示例中,我們僅僅實現了PrintService接口的實現類,因此只需要判斷type參數是否為PrintService類即可。
下一步,我們需要在META-INF/dubbo/internal/目錄下創建一個名為com.alibaba.dubbo.common.extension.ExtensionFactory的文件,文件內容為我們實現的擴展點實現類全限定類名。
比如我們實現的擴展點實現類為com.example.extension.MyExtensionFactory?,那么我們就要在META-INF/dubbo/internal/目錄下創建一個名為com.alibaba.dubbo.common.extension.ExtensionFactory?的文件,并將文件內容寫為com.example.extension.MyExtensionFactory。
最后,我們在程序中就可以使用自定義的擴展點了。示例代碼:
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Main.class);
PrintService printService =
ExtensionLoader.getExtensionLoader(PrintService.class).getExtension("console");
printService.print("hello world!");
在以上示例代碼中,我們通過getExtension()方法來獲取PrintService接口的實現類。getExtension()方法中的參數為擴展點的name屬性,該屬性值默認為“default”。
在本示例中我們將name的值設置為“console”,因此即使用了我們自定義的擴展點實現類。
四、Dubbo的自定義擴展點機制
1、什么是自定義擴展點機制
Dubbo的自定義擴展點機制是在SPI擴展機制的基礎上,增加了自定義擴展點的實現方式。通過Dubbo的擴展機制,我們可以通過配置文件切換Dubbo內部的實現方式,但是對于用戶自己實現的功能模塊,如何進行擴展呢?
這里就需要用到自定義擴展點機制了。
下圖是自定義擴展點機制的詳細時序圖:

自定義擴展點機制
在上圖中:
- 用戶首先將自己實現的擴展點注冊到Dubbo中;
- 然后在需要使用該擴展點的時候,Dubbo會根據擴展點的名稱進行查找并返回相應的擴展點實例;
- 通過這樣的機制,用戶可以靈活地擴展Dubbo的功能,同時也可以讓Dubbo更加適應不同的業務場景。
自定義擴展點的核心思想就是:“面向接口編程,實現類實現接口,接口與實現類通過擴展點Binder關聯。”
其中,Binder的定義可以參考以下的代碼:
public interface ExtensionFactory {
// 返回一個擴展點的代理對象
<T> T getExtension(Class<T> type, String name) throws IllegalStateException;
}
public interface ExtensionLoader<T> {
T getExtension(String name);
}
public interface ExtensionBinder<T> {
// 綁定
void bind(T instance);
// 獲取綁定的擴展對象
T get();
}
public interface ExtensionLoaderListener {
void onLoad();
}
2、自定義擴展點機制的使用示例
為了更好地理解Dubbo的自定義擴展點機制,我們可以通過一個簡單的示例來演示其使用方法。假設我們有一個接口HelloService,我們想要通過自定義擴展點機制,為這個接口添加一個實現類。
首先,我們需要創建一個實現類HelloServiceImpl,該實現類需要實現HelloService接口。
接著,我們需要在resources/META-INF/dubbo目錄下創建一個名為com.xxx.HelloService的文件,該文件中需要指定HelloService接口的實現類名稱。
helloService=com.xxx.HelloServiceImpl
接下來,我們需要在代碼中獲取HelloService接口的實例。這可以通過以下方式實現:
ExtensionLoader<HelloService> loader =
ExtensionLoader.getExtensionLoader(HelloService.class);
HelloService helloService =
loader.getExtension("helloService");
helloService.sayHello();
其中,getExtensionLoader()方法用于獲取擴展點的ExtensionLoader實例,getExtension()方法用于 獲取具體的擴展實例。
在上面的代碼中,我們通過“helloService”這個名稱獲取到了實現了HelloService接口的HelloServiceImpl實例,并調用了其中的sayHello()方法。
通過上述示例,我們可以看出,使用Dubbo的自定義擴展點機制非常簡單,只需要在配置文件中指定實現類的名稱,然后通過getExtensionLoader()和getExtension()方法獲取實例即可。
3、Dubbo的自定義擴展點機制的實現示例
在Dubbo的自定義擴展點機制中,最核心的是ExtensionLoader類和ExtensionFactory類。
其中,ExtensionLoader用于加載和管理擴展實例,ExtensionFactory用于創建擴展實例。
下面,我們將通過一個簡單的示例,演示Dubbo的自定義擴展點機制的具體實現方式。
首先,我們需要定義一個擴展點接口:
public interface HelloService {
String sayHello(String name);
}
接著,我們需要實現該接口的一個實現類:
@SPI("helloWorld")
public class HelloWorldService implements HelloService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
}
在這里,我們使用了@SPI注解來指定該擴展點的默認實現,如果配置文件中沒有指定其他實現,則會使用該默認實現。
接下來,我們需要創建一個名為com.xxx.HelloService的文件,該文件中需要指定擴展點接口的實現類名稱:
helloWorld=com.xxx.HelloWorldService
最后,我們需要在代碼中獲取HelloService接口的實例,這可以通過以下代碼實現:
ExtensionLoader<HelloService> loader =
ExtensionLoader.getExtensionLoader(HelloService.class);
HelloService helloService =
loader.getExtension("helloWorld");
System.out.println(helloService.sayHello("Dubbo"));
在上述代碼中,我們通過getExtensionLoader()方法獲取HelloService接口的ExtensionLoader實例,然后通過getExtension()方法獲取名為“helloWorld”的實現類實例,并調用其中的sayHello()方法。
五、Dubbo的過濾器擴展機制
1、Dubbo的過濾器機制概述

Dubbo的過濾器機制允許在調用前、調用后以及拋出異常時執行一些額外的操作。過濾器在調用鏈路中按順序執行,可以在過濾器中實現各種功能,例如:日志記錄、性能統計、權限控制等。

內置過濾器
Dubbo中內置了多個過濾器,包括:ClassLoader過濾器、Context過濾器、Generic過濾器、Echo過濾器、Token過濾器、AccessLog過濾器等。
下面是Dubbo的過濾器機制的時序圖:

上圖中:
- 服務消費者向服務提供者發送請求時,請求先經過過濾器1;
- 如果過濾器1通過則進一步經過過濾器2;
- 如果過濾器2通過則進一步經過過濾器3;
- 如果過濾器3通過則將請求發送給服務提供者,服務提供者處理請求后將響應返回給服務消費者,響應也會經過相同的過濾器鏈路;
- 如果任意一個過濾器拒絕請求,則直接返回錯誤響應。
2、過濾器擴展機制的使用示例
Dubbo提供了擴展機制,可以在dubbo配置文件中配置過濾器,示例如下:
<dubbo:provider filter="accessLogFilter" />
在上面的例子中,accessLogFilter表示需要使用的過濾器名稱,可以在dubbo配置文件中通過dubbo:filter標簽進行定義。
3、自定義過濾器的實現示例
要實現自定義過濾器,需要按照以下步驟進行:
- 定義一個類實現org.Apache.dubbo.rpc.Filter接口;
- 實現接口中的方法;
- 在META-INF/dubbo目錄下創建一個以org.apache.dubbo.rpc.Filter接口全限定名為名稱的文件,并在文件中添加自定義過濾器的類名。
下面是一個自定義的過濾器示例:
package com.example;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
@Activate(group = "provider")
public class MyFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 在這里實現自己的邏輯
return invoker.invoke(invocation);
}
}
在上面的例子中,我們實現了一個MyFilter過濾器,并使用@Activate注解指定了它是一個provider端的過濾器,然后在invoke()方法中編寫自己的邏輯,最后調用invoker.invoke(invocation)方法來執行調用鏈路中的下一個過濾器或服務。
六、Dubbo的負載均衡擴展機制
1、Dubbo的負載均衡擴展機制概述
負載均衡是分布式系統中的一個重要問題,它可以實現將請求分攤到多個服務提供者上,提高系統的并發能力和可用性。
Dubbo的負載均衡擴展機制允許用戶自定義負載均衡策略,實現更加靈活、適合特定場景的負載均衡算法。
Dubbo內置了多種負載均衡算法,包括隨機、輪詢、最少活躍調用等。
下面是Dubbo的負載均衡擴展機制的時序圖:

負載均衡擴展機制
2、負載均衡擴展機制的使用示例
Dubbo的負載均衡擴展機制可以通過在服務提供方和服務消費方的配置文件中指定負載均衡策略來使用。
例如,在服務提供方的配置文件中可以添加以下配置:
<dubbo:service interface="com.xxx.XxxService" loadbalance="roundrobin" />
在服務消費方的配置文件中可以添加以下配置:
<dubbo:reference interface="com.xxx.XxxService" loadbalance="random" />
這樣就可以實現使用Dubbo內置的輪詢
3、自定義負載均衡策略的實現示例
用戶可以通過實現Dubbo的LoadBalance接口來自定義負載均衡策略。
以下是一個示例:
public class MyLoadBalance implements LoadBalance {
@Override
public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
// 自定義負載均衡算法實現
return invokers.get(0);
}
}
七、Dubbo的容錯機制擴展
1、Dubbo的容錯機制概述
Dubbo的容錯機制是指當Dubbo服務調用出現異常時,Dubbo框架會根據預設的容錯機制進行處理,以保證服務的高可用性。
Dubbo框架默認提供了多種容錯機制,如Failover、Failfast、Failsafe、Failback、Forking等,也支持自定義容錯機制。
Dubbo的容錯機制通常是通過在客戶端代理層實現的,當遠程服務調用出現異常時,客戶端代理會根據預設的容錯機制進行重試或處理,以保證服務的高可用性。

容錯機制
在Dubbo的容錯機制中,ClusterInvoker負責調用遠程服務,并進行容錯處理。當調用遠程服務發生異常時,Dubbo會按照以下順序進行容錯處理:
- ClusterInvoker處理異常;
- 如果ClusterInvoker處理異常失敗,則交由Router處理異常;
- 如果Router處理異常失敗,則交由LoadBalance處理異常;
- 如果LoadBalance處理異常失敗,則拋出異常給InvokerInvocationHandler,最終拋出給Consumer。同時,Dubbo還會將異常信息進行監控,并更新調用統計信息。
2、容錯機制擴展的使用示例
Dubbo默認的容錯機制是Failover,即自動切換重試其他節點,達到容錯和負載均衡的效果。如果需要使用其他容錯機制,可以通過在服務提供方和服務消費方的配置文件中進行配置。
例如,我們可以通過以下方式配置使用Failfast容錯機制:
在服務提供方的配置文件中增加如下配置:
<dubbo:service interface="com.example.service.SomeService" retries="0"/>
在服務消費方的配置文件中增加如下配置:
<dubbo:reference interface="com.example.service.SomeService" check="false" cluster="failfast"/>
這樣,在服務調用出現異常時,Dubbo框架會自動使用Failfast容錯機制進行處理,即只進行一次調用,若調用失敗則立即拋出異常,不進行重試。
3、自定義容錯策略的實現示例
如果需要實現自定義的容錯策略,可以通過繼承org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker?類,并實現org.apache.dubbo.rpc.Invoker接口,來自定義容錯策略的實現。
例如,我們可以通過以下代碼實現一個自定義的容錯策略:
public class MyClusterInvoker<T> extends AbstractClusterInvoker<T> {
public MyClusterInvoker(Directory<T> directory) {
super(directory);
}
@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
// 自定義容錯邏輯
...
}
}
在實現自定義容錯策略后,需要在服務提供方和服務消費方的配置文件中進行配置。
例如,在服務提供方的配置文件中增加如下配置:
<dubbo:service interface="com.example.service.SomeService" cluster="myClusterInvoker"/>
在服務消費方的配置文件中增加如下配置:
<dubbo:reference interface="com.example.service.SomeService" check="false" cluster="myClusterInvoker"/>
這樣,在服務調用時,Dubbo框架會使用我們自定義的MyClusterInvoker容錯策略進行處理。
八、Dubbo的擴展機制實踐
1、實現一個使用自定義擴展點、過濾器、負載均衡器和容錯機制的 Dubbo 服務
在這個實踐中,我們將實現一個使用自定義擴展點、過濾器、負載均衡器和容錯機制的 Dubbo 服務。
2、首先,我們需要定義一個服務接口。
例如,我們可以定義一個名為 SomeService 的服務接口,如下所示:
public interface SomeService {
String sayHello(String name);
}
3、然后,我們需要實現該服務接口。
例如,我們可以實現一個名為 SomeServiceImpl 的服務實現類,如下所示:
public class SomeServiceImpl implements SomeService {
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
}
4、接下來,我們需要配置 Dubbo 的擴展點、過濾器、負載均衡器和容錯機制。
例如,我們可以在服務提供方和服務消費方的配置文件中進行如下配置:
<!-- 擴展點配置 -->
<dubbo:protocol name="dubbo" extensinotallow="com.example.extension.MyProtocol"/>
<!-- 過濾器配置 -->
<dubbo:provider filter="com.example.filter.MyProviderFilter"/>
<dubbo:consumer filter="com.example.filter.MyConsumerFilter"/>
<!-- 負載均衡器配置 -->
<dubbo:reference interface="com.example.service.SomeService" loadbalance="com.example.loadbalance.MyLoadBalance"/>
<!-- 容錯機制配置 -->
<dubbo:service interface="com.example.service.SomeService" cluster="com.example.cluster.MyCluster"/>
<dubbo:reference interface="com.example.service.SomeService" cluster="com.example.cluster.MyCluster"/>
其中,com.example.extension.MyProtocol? 是一個自定義的 Dubbo 協議擴展點實現類,com.example.filter.MyProviderFilter? 和 com.example.filter.MyConsumerFilter? 是自定義的 Dubbo 過濾器實現類,com.example.loadbalance.MyLoadBalance? 是一個自定義的 Dubbo 負載均衡器實現類,com.example.cluster.MyCluster 是一個自定義的 Dubbo 容錯機制實現類。
5、最后,我們可以使用 Dubbo 的 API 在客戶端調用該服務。
例如,我們可以使用如下代碼在客戶端調用該服務:
// 獲取 Dubbo 服務引用
SomeService someService = DubboReferenceBuilder.newBuilder()
.setInterface(SomeService.class)
.setUrl("dubbo://localhost:20880")
.build();
// 調用 Dubbo 服務
String result = someService.sayHello("Dubbo");
System.out.println(result);
這樣,我們就實現了一個使用自定義擴展點、過濾器、負載均衡器和容錯機制的 Dubbo 服務。
本文轉載自微信公眾號「哪吒編程」






