トピックやコンシューマーグループなどの ApsaraMQ for RocketMQ リソースを作成した後、メッセージングを Java アプリケーションに統合できます。このガイドでは、5.x Java SDK の依存関係の追加、インスタンスへの接続、通常メッセージの送信、およびプッシュコンシューマーまたはシンプルコンシューマーでのメッセージの消費方法について説明します。
始める前に
以下が準備できていることを確認してください:
ApsaraMQ for RocketMQ で、リソース (このシリーズのステップ 2 で作成したトピックとコンシューマーグループ) が作成済みであること
IntelliJ IDEA や Eclipse などの Java IDE (この例では IntelliJ IDEA Ultimate を使用します)
SDK 依存関係の追加
IDE で Java プロジェクトを作成します。
次の依存関係を
pom.xmlに追加します:<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client-java</artifactId> <version>5.0.7</version> </dependency>
FAQ:rocketmq-client-java 依存関係を追加した後に ClassNotFoundException: com.google.protobuf.GeneratedMessageV3 が発生した場合はどうすればよいですか?
このエラーは通常、プロジェクト内の古い依存関係 (rocketmq-spring-boot-starter など) に起因する依存関係の競合により、Protobuf クラスの読み込みが妨げられるために発生します。
この問題を解決するには:
プロジェクトに正しい
protobuf-java依存関係が追加されていることを確認するか、バージョンの異なる SDK を別々のモジュールに分離して競合を回避してください。SDK を別々のモジュールに分割できない場合は、
rocketmq-protoおよびprotobuf-javaの依存関係を明示的に追加してください。
シンプルコンシューマーが使用する rocketmq-client-java SDK には、Protobuf のシェーディングされたバージョン (org.apache.rocketmq.shaded.com.google.protobuf) がすでにバンドルされています。ほとんどの場合、com.google.protobuf:protobuf-java を別途追加する必要はありません。
接続パラメーターの収集
コードを記述する前に、ApsaraMQ for RocketMQ コンソールから次の値を収集します:
| パラメーター | 例 | 取得場所 |
|---|---|---|
endpoints | rmq-cn-xxx.{regionId}.rmq.aliyuncs.com:8080 | [インスタンス詳細] ページ > [エンドポイント] タブ。同じ VPC 内の Elastic Compute Service (ECS) インスタンスからアクセスする場合は VPC エンドポイントを使用し、インターネット経由でアクセスする場合はパブリックエンドポイントを使用します。詳細については、「インスタンスのエンドポイントの取得」をご参照ください。 |
topic | normal_test | メッセージの送受信用に作成したトピック。事前に作成しておく必要があります。詳細については、「トピックの作成」をご参照ください。 |
consumerGroup | GID_test | 作成したコンシューマーグループ。事前に作成しておく必要があります。詳細については、「コンシューマーグループの作成」をご参照ください。 |
InstanceId | rmq-cn-xxx | ApsaraMQ for RocketMQ インスタンスの ID。インターネット経由でアクセスされるサーバーレスインスタンスの場合にのみ必要です。 |
| インスタンスのユーザー名 | 1XVg0hzgKm****** | [アクセス制御] ページ > [インテリジェント認証] タブ。詳細については、「インスタンスのユーザー名とパスワードの取得」をご参照ください。 |
| インスタンスのパスワード | ijSt8rEc45****** | ユーザー名と同じ場所。 |
認証情報が必要な場合
ユーザー名、パスワード、名前空間を提供する必要があるかどうかは、アクセス方法によって異なります:
| アクセス方法 | ユーザー名とパスワード | 名前空間 (インスタンス ID) |
|---|---|---|
| VPC (スタンダードインスタンス) | 不要。ブローカーは VPC 情報から認証情報を自動的に取得します。 | 不要。 |
| VPC (サーバーレスインスタンス、認証不要が有効) | 不要。 | 不要。 |
| VPC (サーバーレスインスタンス、認証不要が無効) | 必要。 | 不要。 |
| インターネット (スタンダードインスタンス) | 必要。先にインスタンスでインターネットアクセスを有効にしてください。 | 不要。 |
| インターネット (サーバーレスインスタンス) | 必要。 | 必要。.setNamespace("InstanceId") で設定します。 |
メッセージの送信
プロジェクトに ProducerExample.java ファイルを作成して実行します:
import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;
public class ProducerExample {
public static void main(String[] args) throws ClientException {
// インスタンスのエンドポイント。同じ VPC 内の ECS インスタンスからアクセスする場合は VPC エンドポイントを使用し、インターネット経由でアクセスする場合はパブリックエンドポイントを使用します。
String endpoints = "<your-endpoint>";
// トピック (コンソールで事前に作成する必要があります)
String topic = "<your-topic>";
ClientServiceProvider provider = ClientServiceProvider.loadService();
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
// インターネット経由でアクセスされるサーバーレスインスタンスの場合は、コメントアウトを解除します:
// .setNamespace("<your-instance-id>")
// インターネットアクセス、または認証が必要なサーバーレス VPC の場合は、コメントアウトを解除します:
// .setCredentialProvider(new StaticSessionCredentialsProvider("<instance-username>", "<instance-password>"))
.build();
Producer producer = provider.newProducerBuilder()
.setTopics(topic)
.setClientConfiguration(clientConfiguration)
.build();
Message message = provider.newMessageBuilder()
.setTopic(topic)
.setKeys("messageKey")
.setTag("messageTag")
.setBody("messageBody".getBytes())
.build();
try {
SendReceipt sendReceipt = producer.send(message);
System.out.println(sendReceipt.getMessageId());
} catch (ClientException e) {
e.printStackTrace();
}
}
}プレースホルダーを実際の値に置き換えます:
| プレースホルダー | 説明 |
|---|---|
<your-endpoint> | インスタンスのエンドポイント。例:rmq-cn-xxx.cn-hangzhou.rmq.aliyuncs.com:8080 |
<your-topic> | トピック名。例:normal_test |
<your-instance-id> | インスタンス ID (サーバーレスのインターネットアクセスのみ) |
<instance-username> | インスタンスのユーザー名 (インターネットアクセス、または認証が必要なサーバーレス VPC) |
<instance-password> | インスタンスのパスワード (インターネットアクセス、または認証が必要なサーバーレス VPC) |
.setTopics() をプロデューサーの初期化時に使用すると、トピック設定が事前に検証されます。これは通常メッセージではオプションですが (送信時に動的に検証されるため)、クエリ API の失敗を防ぐためにトランザクションメッセージでは必須です。メッセージの送信に失敗した場合、そのメッセージはサーバーに書き込まれないため、後でコンソールでメッセージ ID を使って検索することはできません。アプリケーションコードで例外 (SendCallback.onException など) をキャッチし、完全なメッセージ内容をログに記録し、ビジネスロジックに基づいて送信を再試行してください。
メッセージの受信
ApsaraMQ for RocketMQ は、2 種類のコンシューマーを提供しています:
| プッシュコンシューマー | シンプルコンシューマー | |
|---|---|---|
| 仕組み | SDK がコールバック (メッセージリスナー) にメッセージを配信します。 | アプリケーションがメッセージをプルし、各メッセージを明示的に確認応答します。 |
| 同時実行 | SDK によって管理されます。 | アプリケーションによって管理されます。 |
| 柔軟性 | 低。SDK が消費フローをカプセル化します。 | 高。アトミックな操作により、カスタムワークフローを構築できます。 |
| 最適な用途 | 受信メッセージを処理する必要があるほとんどのユースケース。 | プル、処理、または確認応答に対してきめ細かな制御が必要なシナリオ。 |
消費フローに対するカスタム制御が必要な場合を除き、プッシュコンシューマーから始めることを推奨します。
rocketmq-spring-boot-starter または rocketmq-v5-client-spring-boot-starter を使用して SDK を Spring Boot と統合する場合、次の制限と設定の違いに注意してください:
rocketmq-spring-boot-starter の
@RocketMQMessageListenerアノテーションは、プッシュコンシューマーのみをサポートします。シンプルコンシューマーが必要な場合は、コードで手動で初期化する必要があります。アノテーションによる設定はサポートされていません。rocketmq-v5-client-spring-boot-starter では、シンプルコンシューマーとその非表示期間の動的な変更も、現在コードでの手動初期化が必要です。これらはアノテーションを介して自動的に注入されません。
v5 スターターの設定ファイルでは、以前の
name-serverパラメーターの代わりにendpointsパラメーターを使用してください。namespaceパラメーターはスターターによって異なります:rocketmq-v5-client-spring-boot-starter ではnamespaceを設定し、rocketmq-spring-boot-starter では代わりにnamespaceV2を設定します。YAML 設定ファイルがこのパラメーターをサポートしていない場合は、コードで設定してください。
プッシュコンシューマー
PushConsumerExample.java ファイルを作成して実行します:
import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.consumer.ConsumeResult;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.FilterExpressionType;
import org.apache.rocketmq.client.apis.consumer.PushConsumer;
import org.apache.rocketmq.shaded.org.slf4j.Logger;
import org.apache.rocketmq.shaded.org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collections;
public class PushConsumerExample {
private static final Logger LOGGER = LoggerFactory.getLogger(PushConsumerExample.class);
private PushConsumerExample() {
}
public static void main(String[] args) throws ClientException, IOException, InterruptedException {
String endpoints = "<your-endpoint>";
String topic = "<your-topic>";
String consumerGroup = "<your-consumer-group>";
final ClientServiceProvider provider = ClientServiceProvider.loadService();
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
// インターネット経由でアクセスされるサーバーレスインスタンスの場合は、コメントアウトを解除します:
// .setNamespace("<your-instance-id>")
// インターネットアクセス、または認証が必要なサーバーレス VPC の場合は、コメントアウトを解除します:
// .setCredentialProvider(new StaticSessionCredentialsProvider("<instance-username>", "<instance-password>"))
.build();
// トピック内のすべてのメッセージをサブスクライブします (tag = "*")
String tag = "*";
FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);
PushConsumer pushConsumer = provider.newPushConsumerBuilder()
.setClientConfiguration(clientConfiguration)
.setConsumerGroup(consumerGroup)
.setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
.setMessageListener(messageView -> {
System.out.println("Consume Message: " + messageView);
return ConsumeResult.SUCCESS;
})
.build();
// コンシューマーを実行し続けます
Thread.sleep(Long.MAX_VALUE);
// コンシューマーを正常にシャットダウンするには、次を呼び出します:
// pushConsumer.close();
}
}ApsaraMQ for RocketMQ 5.x gRPC SDK のプッシュコンシューマーは、内部のローカルバッファキューを使用します。シングルスレッドでメッセージを消費する場合でも、SDK はこのバッファにメッセージをプリフェッチします。ビジネスロジックが各メッセージの処理に長い時間を要する場合、このプリフェッチによりローカルでの待機タイムアウトやリソースの不要な消費が発生する可能性があります。
実行に時間のかかるビジネスロジックには、代わりにシンプルコンシューマー (プルモード) を使用してください。シンプルコンシューマーを使用すると、一度にプルするメッセージの数を正確に制御でき、現在のバッチを処理して確認応答した後にのみ次のバッチをプルします。InvisibleDuration (受信したメッセージが他のコンシューマーから見えなくなる期間、10 秒から 12 時間) を設定して確認応答のタイムアウトを制御し、必要に応じて動的に延長することができます。
シンプルコンシューマー
SimpleConsumerExample.java ファイルを作成して実行します:
import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.FilterExpressionType;
import org.apache.rocketmq.client.apis.consumer.SimpleConsumer;
import org.apache.rocketmq.client.apis.message.MessageId;
import org.apache.rocketmq.client.apis.message.MessageView;
import org.apache.rocketmq.shaded.org.slf4j.Logger;
import org.apache.rocketmq.shaded.org.slf4j.LoggerFactory;
import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
public class SimpleConsumerExample {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleConsumerExample.class);
private SimpleConsumerExample() {
}
public static void main(String[] args) throws ClientException, IOException {
String endpoints = "<your-endpoint>";
String topic = "<your-topic>";
String consumerGroup = "<your-consumer-group>";
final ClientServiceProvider provider = ClientServiceProvider.loadService();
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
// インターネット経由でアクセスされるサーバーレスインスタンスの場合は、コメントアウトを解除します:
// .setNamespace("<your-instance-id>")
// インターネットアクセス、または認証が必要なサーバーレス VPC の場合は、コメントアウトを解除します:
// .setCredentialProvider(new StaticSessionCredentialsProvider("<instance-username>", "<instance-password>"))
.build();
// ロングポーリングのタイムアウト
Duration awaitDuration = Duration.ofSeconds(10);
// トピック内のすべてのメッセージをサブスクライブします (tag = "*")
String tag = "*";
FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);
SimpleConsumer consumer = provider.newSimpleConsumerBuilder()
.setClientConfiguration(clientConfiguration)
.setConsumerGroup(consumerGroup)
.setAwaitDuration(awaitDuration)
.setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
.build();
// 1回のプルあたりの最大メッセージ数
int maxMessageNum = 16;
// 受信後、この期間メッセージは他のコンシューマーから見えなくなります
Duration invisibleDuration = Duration.ofSeconds(10);
// ループでメッセージをポーリングします。リアルタイムで消費するには、複数のスレッドを使用してください。
while (true) {
final List<MessageView> messages = consumer.receive(maxMessageNum, invisibleDuration);
messages.forEach(messageView -> {
System.out.println("Received message: " + messageView);
});
for (MessageView message : messages) {
final MessageId messageId = message.getMessageId();
try {
// 各メッセージを確認応答して、消費結果をブローカーにコミットします
consumer.ack(message);
System.out.println("Message is acknowledged successfully, messageId= " + messageId);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
// コンシューマーを正常にシャットダウンするには、次を呼び出します:
// consumer.close();
}
}メッセージ配信の確認
ApsaraMQ for RocketMQ コンソールで配信ステータスを確認します:
ApsaraMQ for RocketMQ コンソールにログインします。
[インスタンス] ページで、インスタンス名をクリックします。
左側メニューで、[メッセージ追跡] をクリックします。
サーバーレスのインターネットアクセスに必要な SDK バージョン
サーバーレスの ApsaraMQ for RocketMQ インスタンスにインターネット経由でアクセスするには、最小 SDK バージョンが必要です。例の InstanceId を実際のインスタンス ID に置き換えてください。
Java 5.x SDK (rocketmq-client-java)
最小バージョン:5.0.6
ClientConfiguration で名前空間を設定します:
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
.setEndpoints(endpoints)
.setNamespace("InstanceId")
.setCredentialProvider(sessionCredentialsProvider)
.build();Java 5.x SDK (rocketmq-client)
最小バージョン:5.2.0
プロデューサーとコンシューマーで個別に名前空間を設定します:
// プロデューサー
producer.setNamespaceV2("InstanceId");
// コンシューマー
consumer.setNamespaceV2("InstanceId");Java 1.x TCP クライアント SDK
最小バージョン:1.9.0.Final
プロパティで名前空間を設定します:
properties.setProperty(PropertyKeyConst.Namespace, "InstanceId");FAQ:メッセージ送信時に "The instance version does not support setting user properties" というエラーが発生した場合はどうすればよいですか?
このエラーは通常、SDK のバージョンが古すぎることが原因です。解決するには、SDK をバージョン 1.9.1.Final 以降にアップグレードして再試行してください。
次のステップ
他のプログラミング言語でメッセージを送受信する。詳細は「SDK の概要」をご参照ください。
PushConsumer と SimpleConsumer の詳細について学習する。