发送消息
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 对象作为消息数据内容的参数。JmsTemplate 中重载的 convertAndSend() 和 receiveAndConvert() 方法将转换过程委托给 MessageConverter 接口的实例。该接口定义了一个简单的契约,用于在 Java 对象和 JMS 消息之间进行转换。默认实现(SimpleMessageConverter)支持 String 与 TextMessage、byte[] 与 BytesMessage 以及 java.util.Map 与 MapMessage 之间的转换。通过使用转换器,您和您的应用程序代码可以专注于通过 JMS 发送或接收的业务对象,而无需关心其如何表示为 JMS 消息的细节。
沙箱当前包含一个 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.TextMessage、jakarta.jms.BytesMessage 等。若需支持通用消息负载的契约,请改用 org.springframework.messaging.converter.MessageConverter,
并配合 JmsMessagingTemplate 或更推荐使用 JmsClient 作为您的核心委托。 |
使用SessionCallback和ProducerCallback on JmsTemplate
虽然发送操作涵盖了许多常见的使用场景,但有时您可能希望对 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 org.springframework.messaging.core.MessagePostProcessor 的 Message 可以实现这一功能,
当它被配置到 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();
}
}
}