ハードコアな Java テクノロジーを共有する金漁師のWang Youzhi
が、バケツを持って走り回る Java の人々のグループに加わりました。一緒に裕福な Java の人々
前回の記事 ではサービスガバナンスの観点からDUbboが提供する機能を紹介しましたが、今回はDubboが提供する他の機能について見ていきます。サービス ガバナンスの記事と同様、この記事の目的は、サービスの管理と制御において Dubbo が提供する機能の使い方を学ぶことですが、実装原則はまだ含まれていません。
工学構造
うーん~~
これは、コンピューターが伸縮しすぎていて、IDEA がメモリをかなり消費しているため、サブプロジェクトに従ってテスト プロジェクトをマージしました。現在使用しているプロジェクト構造は次のとおりです。
サブモジュール名は、構成メソッド + 関数の 2 つの部分で構成されます。例: XMLProvider (XML 構成メソッドに基づくサービス プロバイダーを意味します)。
ヒント: IDEA は「記憶のライオン」CLion に追いつきつつあります。
ローカルスタブ(スタブ)
Dubbo を使用する場合、サービス コンシューマはインターフェイスのみを統合し、すべての実装はサービス プロバイダ上で行われます。ただし、シナリオによっては、サービス コンシューマが何らかのロジック処理を完了して、RPC インタラクションによるパフォーマンスの消費を削減できることを期待します。 : パラメータ検証をサービス ユーザーに配置して、サービス呼び出し元とのネットワーク インタラクションを 1 つ削減します。
このシナリオでは、Dubbo が提供するローカル スタブ機能を使用できます。サービスプロバイダーのエンジニアリング構造は次のとおりです。
外部サービスを提供するインターフェイス 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 を追加します。プロジェクト構造は次のとおりです。
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);
}
}
この時点でのプロジェクト構造を見てください。
次は 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 から始まります) はコールバック パラメーターです。コールバックは、コールバックの合計数ではなく、同じ長いリンクの下でのコールバックの数を制限します。
ヒント: 実際の支払いビジネス シナリオでは、非同期処理の傾向が強くなります。たとえば、サービス プロバイダーが支払いを受け取ると、支払いビジネスを処理するための新しいスレッドが開始され、通知インターフェイスが呼び出され、メイン スレッドがそれを返します。支払いリクエストは正常に受信されました。
非同期呼び出し
非同期呼び出しにより、サービス プロバイダーは、バックグラウンドで要求処理を実行し続けながら、すぐに応答を返すことができます。サービス コンシューマーが応答結果を要求すると、サービス プロバイダーは結果を返します。
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 プロジェクトを準備します。プロジェクトの構造は次のとおりです。
インターフェイスはプロジェクト、つまり実装クラス 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 テクノロジーを共有する金融マン。