Dubbo の高度な機能: サービス コントロール

ハードコアな Java テクノロジーを共有する金漁師のWang Youzhi
が、バケツを持って走り回る Java の人々のグループに加わりました。一緒に裕福な Java の人々

前回の記事 ではサービスガバナンスの観点からDUbboが提供する機能を紹介しましたが、今回はDubboが提供する他の機能について見ていきます。サービス ガバナンスの記事と同様、この記事の目的は、サービスの管理と制御において Dubbo が提供する機能の使い方を学ぶことですが、実装原則はまだ含まれていません。

工学構造

うーん~~

これは、コンピューターが伸縮しすぎていて、IDEA がメモリをかなり消費しているため、サブプロジェクトに従ってテスト プロジェクトをマージしました。現在使用しているプロジェクト構造は次のとおりです。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/6f26e516-ce78-49d8-ba20-cb4e23826805.png

サブモジュール名は、構成メソッド + 関数の 2 つの部分で構成されます。例: XMLProvider (XML 構成メソッドに基づくサービス プロバイダーを意味します)。

ヒント: IDEA は「記憶のライオン」CLion に追いつきつつあります。

ローカルスタブ(スタブ)

Dubbo を使用する場合、サービス コンシューマはインターフェイスのみを統合し、すべての実装はサービス プロバイダ上で行われます。ただし、シナリオによっては、サービス コンシューマが何らかのロジック処理を完了して、RPC インタラクションによるパフォーマンスの消費を削減できることを期待します。 : パラメータ検証をサービス ユーザーに配置して、サービス呼び出し元とのネットワーク インタラクションを 1 つ削減します。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/8dd6c9c7-451c-4681-b225-8f823cc4092c.jpeg

このシナリオでは、Dubbo が提供するローカル スタブ機能を使用できます。サービスプロバイダーのエンジニアリング構造は次のとおりです。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/0a7169a4-cef6-40f8-afe5-94206631503a.png

外部サービスを提供するインターフェイス XMLProviderService は、xml-provider-api モジュールで定義されており、コードは次のとおりです。

public interface XMLProviderService {
  String say(String message);
}

インターフェイス スタブ XMLProviderServiceStub のコードは次のとおりです。

public class XMLProviderServiceStub implements XMLProviderService {
  
  private final XMLProviderService xmlProviderService;
  
  public XMLProviderServiceStub(XMLProviderService xmlProviderService) {
    this.xmlProviderService = xmlProviderService;
  }
  
  @Override
  public String say(String message) {
    if (StringUtils.isBlank(message)) {
      return "message不能为空!";
    }
    
    try {
      return this.xmlProviderService.say(message);
    } catch (Exception e) {
      return "远程调用失败:" + e.getMessage();
    }
  }
}

次に、サービス コンシューマーのプロジェクトでインターフェイス スタブを構成します。

<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" stub="com.wyz.api.stub.XMLProviderServiceStub"/>

ヒント: ローカル スタブを使用するには、スタブの実装クラスに、Proxy インスタンス (サービス コンシューマーによって生成された Proxy インスタンス) を渡すコンストラクターが必要です。

局所迷彩(モック)

ローカルカモフラージュとは、 「 Dubbo の高度な機能: サービス ガバナンス」で説明したサービスの低下のことですが、今日は少し追加します。ローカル マスカレードはローカル スタブのサブセットです。ローカル スタブは RPC 呼び出しリンク内のさまざまなエラーと例外を処理できますが、ローカル マスカレードはフォールト トレラントな処理を必要とする RpcException (ネットワーク障害、応答タイムアウトなど) の処理に重点を置いています。 。

XMLProviderService にローカル マスカレード サービス XMLProviderServiceMock を追加します。プロジェクト構造は次のとおりです。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/37396cfe-7f16-4a7b-aac4-6e9a91e59edd.png

XMLProviderServiceMock のコードは次のとおりです。

public class XMLProviderServiceMock implements XMLProviderService {
  
  @Override
  public String say(String message) {
    return "服务出错了!";
  }
}

構成ファイルは次のように構成できます。

<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" mock="true"/>

この構成では、Mock の実装は「インターフェイス名 + Mock サフィックス」の方法に従って名前を付ける必要があります。この名前付け方法を使用したくない場合は、完全修飾名を使用できます。

<dubbo:reference id="xmlProviderService" interface="com.wyz.api.XMLProviderService" mock="com.wyz.api.mock.XMLProviderServiceMock"/>

Tips : もう一度モックを「繰り返す」のは、前の記事でミスがあったためです。<dubbo:reference>ラベルにやるべき設定を書いたのです<dubbo:service>が、エラーの理由はまだ機能していません。 「紙に書かれたことはいつも浅いですが、この問題は実践しなければならないとは決して知りません」というフレーズを遵守しました。

パラメータコールバック

Dubbo は、サービス プロバイダーがサービス コンシューマを「リバース」呼び出すことができるように、パラメーター コールバック関数をサポートしています。この関数は、ロング リンクによって生成されたリバース プロキシに基づいて実装されており、その効果は非同期呼び出しと似ています。支払いの例を見てみましょう。

PaymentService インターフェイスを XMLProvider プロジェクトの xml-provider-api モジュールに追加し、PaymentService の結果を通知する PaymentNotifyService を追加します。

public interface PaymentService {
  void payment(String cardNo, PaymentNotifyService paymentNotifyService);
}

public interface PaymentNotifyService {
  void paymentNotify(String message);
}

PaymentService インターフェイスは、XMLProvider プロジェクトの xml-provider-service モジュールに実装されています。

public class PaymentServiceImpl implements PaymentService {
  @Override
  public void payment(String cardNo, PaymentNotifyService paymentNotifyService) {
    System.out.println("向卡号[" + cardNo + "]付钱!");
    // 业务逻辑
    paymentNotifyService.paymentNotify("付款成功");
  }
}

PaymentService#paymentメソッドを実行し、PaymentNotifyService#paymentNotifyメソッドを呼び出して実行結果をサービス呼び出し元に通知します。

XMLConsumer プロジェクトに PaymentNotifyService インターフェースを実装します。

public class PaymentNotifyServiceImpl implements PaymentNotifyService {
  @Override
  public void paymentNotify(String message) {
    System.out.println("支付结果:" + message);
  }
}

この時点でのプロジェクト構造を見てください。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/a45fd029-2f1b-4f8b-83c1-c54997100c6d.png

次は XML 設定です。パラメータ コールバックでは、サービス プロバイダーの XMLProvider プロジェクトの xml-provider-service モジュールの設定に注意する必要があります。

<bean id="paymentServiceImpl" class="com.wyz.service.impl.PaymentServiceImpl"/>
<dubbo:service interface="com.wyz.api.PaymentService" ref="paymentServiceImpl" callbacks="10">
  <dubbo:method name="payment">
    <dubbo:argument index="1" callback="true"/>
  </dubbo:method>
</dubbo:service>

構成は4 行目で<dubbo:argument index="1" callback="true"/>決まりますPaymentService#payment。メソッドの 2 番目のパラメーター (インデックスは 0 から始まります) はコールバック パラメーターです。コールバックは、コールバックの合計数ではなく、同じ長いリンクの下でのコールバックの数を制限します。

ヒント: 実際の支払いビジネス シナリオでは、非同期処理の傾向が強くなります。たとえば、サービス プロバイダーが支払いを受け取ると、支払いビジネスを処理するための新しいスレッドが開始され、通知インターフェイスが呼び出され、メイン スレッドがそれを返します。支払いリクエストは正常に受信されました。

非同期呼び出し

非同期呼び出しにより、サービス プロバイダーは、バックグラウンドで要求処理を実行し続けながら、すぐに応答を返すことができます。サービス コンシューマーが応答結果を要求すると、サービス プロバイダーは結果を返します。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/8dd1ba48-cfc6-4e05-ba5b-2a7a5dcb5170.jpeg

DUbbo は 2 つの非同期呼び出しメソッドをサポートしています。

  • CompletableFuture インターフェースを使用する
  • RpcContext を使用する

DUbbo 2.7 以降、DUbbo は非同期プログラミングの基礎としてCompletableFutureインターフェイスを使用します。

CompletableFuture を使用して非同期呼び出しを実装する

まず、CompletableFuture を使用して非同期呼び出しを実装し、CompletableFutureAsyncService インターフェイスを宣言する方法を見てみましょう。

public interface CompletableFutureAsyncService {
  CompletableFuture<String> async(String message);
}

次に、インターフェイスの実装が続きます。

public class CompletableFutureAsyncServiceImpl implements CompletableFutureAsyncService {
  @Override
  public CompletableFuture<String> async(String message) {
    return CompletableFuture.supplyAsync(() -> {
      System.out.println(Thread.currentThread().getName() + " say : " + message);
      
      try {
        TimeUnit.SECONDS.sleep(10);
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
      return "异步调用成功!";
    });
  }
}

XML 構成は、一般的な Dubbo RPC インターフェース構成、つまり xml-provider-service モジュールの構成と同じです。

<bean id="completableFutureAsyncServiceImpl" class="com.wyz.service.impl.CompletableFutureAsyncServiceImpl" />
<dubbo:service interface="com.wyz.api.CompletableFutureAsyncService" ref="completableFutureAsyncServiceImpl" />

XMLConsumer モジュールの構成:

<dubbo:reference id="completableFutureAsyncService" interface="com.wyz.api.CompletableFutureAsyncService"/>

使い方も非常に簡単です。

CompletableFuture<String> completableFuture = completableFutureAsyncService.async("Hello");
System.out.println(completableFuture.get());

ヒント

  • Dubbo で CompletableFuture を使用する場合と CompletableFuture を単独で使用する場合に違いはありません~~
  • CompletableFutureAsyncServiceImpl の実装でインターフェイス名を出力する目的は、非同期呼び出しの効果を明確に示すことです。
  • CompletableFuture#supplyAsync(Supplier<U> supplier)デフォルトではForkJoinPool#commonPool();を使用します。
  • オーバーロードされたメソッドでは、CompletableFuture#supplyAsync(Supplier<U> supplier, Executor executor)カスタム スレッド プールを使用できます。

AsyncContext を使用して非同期呼び出しを実装する

CompletableFuture の使用に加えて、Dubbo によって定義された AsyncContext を介して非同期呼び出しを実装することもできます。最初にインターフェイスとインターフェイス実装を作成しましょう。

public interface RpcContextAsyncService {
  String async(String message);
}

public class RpcContextAsyncServiceImpl implements RpcContextAsyncService {
  
  @Override
  public String async(String message) {
    final AsyncContext asyncContext = RpcContext.startAsync();
    new Thread(() -> {
      asyncContext.signalContextSwitch();
      asyncContext.write(Thread.currentThread().getName() + " say : " + message);
    }).start();
    // 异步调用中,这个返回值完全没有意义
    return null;
  }
}

サービス プロバイダーの構成は、他の Dubbo インターフェイスの構成と同じです。

<bean id="rpcContextAsyncServiceImpl" class="com.wyz.service.impl.RpcContextAsyncServiceImpl"/>
<dubbo:service interface="com.wyz.api.RpcContextAsyncService" ref="rpcContextAsyncServiceImpl"/>

次に、サービス コンシューマの構成です。これには async パラメータを追加する必要があります。

<dubbo:reference id="rpcContextAsyncService" interface="com.wyz.api.RpcContextAsyncService" async="true"/>

最後に、サービス コンシューマで RPC インターフェイスを呼び出します。

rpcContextAsyncService.async("Thanks");

Future<String> future = RpcContext.getServiceContext().getFuture();
System.out.println(future.get());

一般化コール

Dubbo の汎用呼び出しは、サービス プロバイダー API (SDK) に依存せずにサービスを呼び出す実装方法を提供します。主なシナリオはゲートウェイ プラットフォームの実装にありますが、通常、ゲートウェイの実装は他のサービスの API (SDK) に依存すべきではありません。

Dubbo は公式に 3 つの一般化呼び出しメソッドを提供します。

  • API を介した汎用呼び出しの使用
  • Spring 経由の汎用呼び出しの使用 (XML 形式)
  • Protobuf オブジェクト一般化呼び出し

ここでは、XML 形式で汎用呼び出しを構成する方法を紹介します。

準備

まず、サービス プロビジョニング用の GenericProvider プロジェクトを準備します。プロジェクトの構造は次のとおりです。

https://alidocs.oss-cn-zhangjiakou.aliyuncs.com/res/4EZlwNDQ7kPYOxAY/img/834b8cb4-43b8-40e8-a0e4-1f9a30eb6263.png

インターフェイスはプロジェクト、つまり実装クラス GenericProviderService および GenericProviderServiceImpl で定義されます。コードは次のとおりです。

public interface GenericProviderService {
  String say(String message);
}

public class GenericProviderServiceImpl implements GenericProviderService {
  @Override
  public String say(String message) {
    return "GenericProvider say:" + message;
  }
}

generic-dubbo-provider.xml では、GenericProvider によって提供されるサービスのみを通常どおりに構成する必要があります。

<bean id="genericProviderServiceImpl" class="com.wyz.service.impl.GenericProviderServiceImpl"/>
<dubbo:service interface="com.wyz.service.api.GenericProviderService" ref="genericProviderServiceImpl" generic="true"/>

application.yml ファイルの構成については詳しく説明しません。

サービスコンシューマの構成

XMLConsumer プロジェクトに戻り、最初に Dubbo サービス参照を構成し、次のコンテンツを xml-dubbo-consumer.xml に追加します。

<dubbo:reference id="genericProviderService" generic="true" interface="com.wyz.service.api.GenericProviderService"/>

パラメータ generic は、これが汎用呼び出しサービスであることを宣言します。このとき、IDEA はinterface="com.wyz.service.api.GenericProviderService"それを赤色でマークし、「クラス 'GenericProviderService' を解決できません」というプロンプトを表示します。GenericProviderService インターフェイスは com.wyz.service.api パッケージの下に存在しないため、これに注意を払う必要はありません。

次に、GenericProviderService インターフェイスを使用してみましょう。

ApplicationContext context = SpringContextUtils.getApplicationContext();
// genericProviderService是XML中定义的服务id
GenericService genericService = (GenericService) context.getBean("genericProviderService");

// $invoke的3个参数分别为:方法名,参数类型,参数
Object result = genericService.$invoke("say", new String[]{"java.lang.String"}, new Object[]{"wyz"});
System.out.println(result);

このようにして、ApplicationContext を通じて GenericProviderService インターフェイスによって提供されるサービスを取得できます。

ヒント: ApplicationContext を取得するには SpringContextUtils を使用します。コードは次のとおりです。

@Component
public class SpringContextUtils implements ApplicationContextAware {
  private static ApplicationContext applicationContext = null;
  
  public static ApplicationContext getApplicationContext() {
    return SpringContextUtils.applicationContext;
  }
  
  @Override
  public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
    SpringContextUtils.applicationContext = applicationContext;
  }
}

エピローグ

さて、これまでのところ、私たちは Dubbo の共通機能の構成と使用法について知り、学んできました。もちろん、何年もの開発を経て、Dubbo はこれよりもはるかに多くの機能を提供します。さらに詳しく知りたい場合は、ドキュメントを参照してください。」「入門から習得までの Apache Dubbo マイクロサービス フレームワーク」はAlibaba によって提供されます。

次回の記事では、サービス登録部分から Dubbo の実装原理の検討を正式に開始します。


この記事が役に立った場合は、たくさんの賞賛とサポートをお願いします。記事に間違いがあった場合は、批判と修正をお願いします。最後に、皆さんもぜひ、ハードコア Java テクノロジーを共有する金融マン

おすすめ

転載: blog.csdn.net/wyz_1945/article/details/131797679