このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring Framework 6.2.12 を使用してください!

メッセージの送信

JmsTemplate には、メッセージを送信するための多くの便利なメソッドが含まれています。送信メソッドは、jakarta.jms.Destination オブジェクトを使用して宛先を指定し、他のメソッドは JNDI ルックアップで String を使用して宛先を指定します。宛先引数を取らない send メソッドは、デフォルトの宛先を使用します。

次の例では、MessageCreator コールバックを使用して、提供された Session オブジェクトからテキストメッセージを作成します。

import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSException;
import jakarta.jms.Message;
import jakarta.jms.Queue;
import jakarta.jms.Session;

import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.JmsTemplate;

public class JmsQueueSender {

	private JmsTemplate jmsTemplate;
	private Queue queue;

	public void setConnectionFactory(ConnectionFactory cf) {
		this.jmsTemplate = new JmsTemplate(cf);
	}

	public void setQueue(Queue queue) {
		this.queue = queue;
	}

	public void simpleSend() {
		this.jmsTemplate.send(this.queue, new MessageCreator() {
			public Message createMessage(Session session) throws JMSException {
				return session.createTextMessage("hello queue world");
			}
		});
	}
}

前の例では、JmsTemplate は、参照を ConnectionFactory に渡すことによって構築されます。別の方法として、引数なしのコンストラクターと connectionFactory が提供され、JavaBean スタイルでインスタンスを構築するために使用できます(BeanFactory またはプレーン Java コードを使用)。または、Spring の JmsGatewaySupport コンビニエンス基本クラスから派生することを検討してください。この基本クラスは、JMS 構成用に事前作成された Bean プロパティを提供します。

send(String destinationName, MessageCreator creator) メソッドを使用すると、宛先の文字列名を使用してメッセージを送信できます。これらの名前が JNDI に登録されている場合、テンプレートの destinationResolver プロパティを JndiDestinationResolver のインスタンスに設定する必要があります。

JmsTemplate を作成し、デフォルトの宛先を指定した場合、send(MessageCreator c) はその宛先にメッセージを送信します。

JMS メッセージコンバーターの使用

ドメインモデルオブジェクトの送信を容易にするために、JmsTemplate には、メッセージのデータコンテンツの引数として Java オブジェクトを受け取るさまざまな send メソッドがあります。JmsTemplate のオーバーロードされたメソッド convertAndSend() および receiveAndConvert() メソッドは、変換プロセスを MessageConverter インターフェースのインスタンスに委譲します。このインターフェースは、Java オブジェクトと JMS メッセージの間で変換するための単純な契約を定義します。デフォルトの実装(SimpleMessageConverter)は、String と TextMessagebyte[]BytesMessage の間、および java.util.Map と MapMessage の間の変換をサポートします。コンバーターを使用することにより、ユーザーとアプリケーションコードは、JMS を介して送受信されるビジネスオブジェクトに焦点を当てることができ、JMS メッセージとしてどのように表現されるかについての詳細を気にする必要はありません。

現在、サンドボックスには MapMessageConverter が含まれています。MapMessageConverter は、反射を使用して JavaBean と MapMessage を変換します。自分で実装できる他の一般的な実装の選択肢は、既存の XML マーシャリングパッケージ(JAXB や XStream など)を使用してオブジェクトを表す TextMessage を作成するコンバーターです。

コンバータークラス内に一般的にカプセル化できないメッセージのプロパティ、ヘッダー、本文の設定に対応するために、MessagePostProcessor インターフェースでは、変換後、送信前にメッセージにアクセスできます。次の例は、java.util.Map がメッセージに変換された後にメッセージヘッダーとプロパティを変更する方法を示しています。

import java.util.HashMap;
import java.util.Map;

import jakarta.jms.JMSException;
import jakarta.jms.Message;

import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessagePostProcessor;

public class JmsSenderWithConversion {

	private JmsTemplate jmsTemplate;

	public void sendWithConversion() {
		Map<String, Object> map = new HashMap<>();
		map.put("Name", "Mark");
		map.put("Age", 47);
		jmsTemplate.convertAndSend("testQueue", map, new MessagePostProcessor() {
			public Message postProcessMessage(Message message) throws JMSException {
				message.setIntProperty("AccountID", 1234);
				message.setJMSCorrelationID("123-00001");
				return message;
			}
		});
	}

}

これにより、次の形式のメッセージが生成されます。

MapMessage={
	Header={
		... standard headers ...
		CorrelationID={123-00001}
	}
	Properties={
		AccountID={Integer:1234}
	}
	Fields={
		Name={String:Mark}
		Age={Integer:47}
	}
}
この JMS 固有の org.springframework.jms.support.converter.MessageConverter 配置は、JMS メッセージ型で動作し、jakarta.jms.TextMessagejakarta.jms.BytesMessage などへの即時変換を担当します。汎用メッセージペイロードをサポートする契約の場合は、代わりに org.springframework.messaging.converter.MessageConverter を JmsMessagingTemplate とともに使用するか、できれば JmsClient を主要デリゲートとして使用します。

JmsTemplate で SessionCallback と ProducerCallback を使用する

送信操作は多くの一般的な使用シナリオをカバーしていますが、JMS Session または MessageProducer で複数の操作を実行したい場合があります。SessionCallback と ProducerCallback は、それぞれ JMS Session と Session / MessageProducer ペアを公開します。JmsTemplate の execute() メソッドは、これらのコールバックメソッドを実行します。

JmsClient でメッセージを送信する

import jakarta.jms.ConnectionFactory;

import org.springframework.jms.core.JmsClient;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;

public class JmsClientSample {

	private final JmsClient jmsClient;

	public JmsClientSample(ConnectionFactory connectionFactory) {
		// For custom options, use JmsClient.builder(ConnectionFactory)
		this.jmsClient = JmsClient.create(connectionFactory);
	}

	public void sendWithConversion() {
		this.jmsClient.destination("myQueue")
				.withTimeToLive(1000)
				.send("myPayload");  // optionally with a headers Map next to the payload
	}

	public void sendCustomMessage() {
		Message<?> message = MessageBuilder.withPayload("myPayload").build();  // optionally with headers
		this.jmsClient.destination("myQueue")
				.withTimeToLive(1000)
				.send(message);
	}
}

送信メッセージの後処理

アプリケーションは、送信前にメッセージをインターセプトする必要があることがよくあります。たとえば、すべての送信メッセージにメッセージプロパティを追加する場合などです。spring-messaging Message をベースとした org.springframework.messaging.core.MessagePostProcessor は、JmsClient 上で設定することでこれを実現できます。send および sendAndReceive メソッドで送信されるすべての送信メッセージに使用されます。

これは、すべての送信メッセージに "tenantId" プロパティを追加するインターセプターの例です。

import jakarta.jms.ConnectionFactory;

import org.springframework.jms.core.JmsClient;
import org.springframework.messaging.Message;
import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.messaging.support.MessageBuilder;

public class JmsClientWithPostProcessor {

	private final JmsClient jmsClient;

	public JmsClientWithPostProcessor(ConnectionFactory connectionFactory) {
		this.jmsClient = JmsClient.builder(connectionFactory)
				.messagePostProcessor(new TenantIdMessageInterceptor("42"))
				.build();
	}

	public void sendWithPostProcessor() {
		this.jmsClient.destination("myQueue")
				.withTimeToLive(1000)
				.send("myPayload");
	}

	static class TenantIdMessageInterceptor implements MessagePostProcessor {

		private final String tenantId;

		public TenantIdMessageInterceptor(String tenantId) {
			this.tenantId = tenantId;
		}

		@Override
		public Message<?> postProcessMessage(Message<?> message) {
			return MessageBuilder.fromMessage(message)
					.setHeader("tenantId", this.tenantId)
					.build();
		}
	}
}