圖解Dubbo,6 種擴充套件機制詳解

架構師修行手冊發表於2023-04-12

來源:哪吒程式設計

大家好,我是哪吒。

今天詳細的分解一下Dubbo的擴充套件機制,實現快速入門,豐富個人簡歷,提高面試level,給自己增加一點談資,秒變面試小達人,BAT不是夢。

三分鐘你將學會:

  1. Dubbo的自適應擴充套件機制
  2. Dubbo的SPI擴充套件機制
  3. Dubbo的自定義擴充套件點機制
  4. Dubbo的過濾器擴充套件機制
  5. Dubbo的負載均衡擴充套件機制;
  6. Dubbo的容錯機制擴充套件;

一、Dubbo擴充套件機制的概述

Dubbo是一個高效能的分散式服務框架,廣泛應用於各種規模和種類的企業級專案中。在實際應用過程中,Dubbo的核心能力是擴充套件機制,它可以讓Dubbo具有更強的可定製化能力,也可以讓Dubbo更好地適應各種應用場景。

圖解Dubbo,6 種擴充套件機制詳解

Dubbo的擴充套件機制主要包括:自適應擴充套件機制、SPI擴充套件機制、自定義擴充套件點機制、過濾器擴充套件機制、負載均衡擴充套件機制和容錯機制擴充套件

這些機制使得Dubbo的使用更加靈活方便,可以滿足不同需要的業務場景,也可以根據實際情況來選擇合適的擴充套件機制。

在Dubbo的擴充套件機制中,尤其需要注意自定義擴充套件點機制和SPI擴充套件機制。這些機制是Dubbo中較為重要和常用的擴充套件機制,充分了解這些機制可以讓應用程式更加靈活和可定製。

下圖展示了Dubbo擴充套件機制的呼叫流程:

圖解Dubbo,6 種擴充套件機制詳解

上圖中,Dubbo客戶端首先會透過ExtensionLoader載入需要使用的擴充套件點,ExtensionLoader會根據客戶端傳入的擴充套件點名和配置,建立對應的擴充套件點例項,並返回給客戶端,客戶端再透過返回的擴充套件點例項呼叫相應的方法。

二、Dubbo的自適應擴充套件機制

1、什麼是自適應擴充套件機制

自適應擴充套件機制是Dubbo提供的一種機制,它可以使Dubbo框架根據實際使用情況動態地選擇不同的擴充套件實現,從而達到最優的效果。

自適應擴充套件機制的實現方式是透過在擴充套件介面的代理類中,根據實際情況動態地生成對應擴充套件實現的代理類例項。

下圖是自適應擴充套件機制的詳細時序圖:

圖解Dubbo,6 種擴充套件機制詳解

上圖中

  1. Client先呼叫ExtensionLoader載入擴充套件點,並解析配置檔案;
  2. ExtensionLoader根據配置檔案查詢實現類
  3. 然後建立一個AdaptiveExtension的代理物件,並將該代理物件返回給Client;
  4. Client呼叫代理物件的方法時,AdaptiveExtension會根據配置使用具體的擴充套件點實現,並將呼叫轉發給具體的擴充套件點實現;
  5. 最後將結果返回給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 擴充套件機制的工作流程:

圖解Dubbo,6 種擴充套件機制詳解

上圖描述了 Dubbo SPI 擴充套件機制的工作流程,其中:

  1. 使用者向 Dubbo Framework 請求獲取 ExtensionLoader,ExtensionLoader 是 Dubbo SPI 擴充套件機制的核心類;
  2. Dubbo Framework 載入 ExtensionLoader,並返回給使用者;
  3. 使用者呼叫 ExtensionLoader 的方法;
  4. ExtensionLoader 根據指定的 Extension 介面,透過 SPI 機制載入 Extension 實現;
  5. 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> 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,6 種擴充套件機制詳解

在上圖中

  1. 使用者首先將自己實現的擴充套件點註冊到Dubbo中;
  2. 然後在需要使用該擴充套件點的時候,Dubbo會根據擴充套件點的名稱進行查詢並返回相應的擴充套件點例項;
  3. 透過這樣的機制,使用者可以靈活地擴充套件Dubbo的功能,同時也可以讓Dubbo更加適應不同的業務場景。

自定義擴充套件點的核心思想就是:“面向介面程式設計,實現類實現介面,介面與實現類透過擴充套件點Binder關聯。”

其中,Binder的定義可以參考以下的程式碼:

public interface ExtensionFactory {
    // 返回一個擴充套件點的代理物件
    <T> getExtension(Class<T> type, String name) throws IllegalStateException;
}

public interface ExtensionLoader<T{
    getExtension(String name);
}

public interface ExtensionBinder<T{
    // 繫結
    void bind(T instance);
    // 獲取繫結的擴充套件物件
    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,6 種擴充套件機制詳解

Dubbo的過濾器機制允許在呼叫前、呼叫後以及丟擲異常時執行一些額外的操作。過濾器在呼叫鏈路中按順序執行,可以在過濾器中實現各種功能,例如:日誌記錄、效能統計、許可權控制等。

圖解Dubbo,6 種擴充套件機制詳解

Dubbo中內建了多個過濾器,包括:ClassLoader過濾器、Context過濾器、Generic過濾器、Echo過濾器、Token過濾器、AccessLog過濾器等

下面是Dubbo的過濾器機制的時序圖:

圖解Dubbo,6 種擴充套件機制詳解

上圖中

  1. 服務消費者向服務提供者傳送請求時,請求先經過過濾器1;
  2. 如果過濾器1透過則進一步經過過濾器2;
  3. 如果過濾器2透過則進一步經過過濾器3;
  4. 如果過濾器3透過則將請求傳送給服務提供者,服務提供者處理請求後將響應返回給服務消費者,響應也會經過相同的過濾器鏈路;
  5. 如果任意一個過濾器拒絕請求,則直接返回錯誤響應。

2、過濾器擴充套件機制的使用示例

Dubbo提供了擴充套件機制,可以在dubbo配置檔案中配置過濾器,示例如下:

<dubbo:provider filter="accessLogFilter" />

在上面的例子中,accessLogFilter表示需要使用的過濾器名稱,可以在dubbo配置檔案中透過dubbo:filter標籤進行定義。

3、自定義過濾器的實現示例

要實現自定義過濾器,需要按照以下步驟進行:

  1. 定義一個類實現org.apache.dubbo.rpc.Filter介面;
  2. 實現介面中的方法;
  3. 在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的負載均衡擴充套件機制的時序圖:

圖解Dubbo,6 種擴充套件機制詳解

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,6 種擴充套件機制詳解

在Dubbo的容錯機制中,ClusterInvoker負責呼叫遠端服務,並進行容錯處理。當呼叫遠端服務發生異常時,Dubbo會按照以下順序進行容錯處理:

  1. ClusterInvoker處理異常;
  2. 如果ClusterInvoker處理異常失敗,則交由Router處理異常;
  3. 如果Router處理異常失敗,則交由LoadBalance處理異常;
  4. 如果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<Textends 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" extension="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.MyProviderFiltercom.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 服務

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027824/viewspace-2945254/,如需轉載,請註明出處,否則將追究法律責任。

相關文章