跳到主要内容
版本:7.0.3

发送消息

Hunyuan 7b 中英对照 Sending a Message

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)支持 StringTextMessagebyte[]BytesMessage、以及 java.util.MapMapMessage 之间的转换。通过使用这些转换器,你和你的应用程序代码可以专注于通过 JMS 发送或接收的业务对象,而无需关心其如何被表示为 JMS 消息的细节。

沙箱环境中目前包含一个MapMessageConverter,它通过反射机制在JavaBeanMapMessage之间进行转换。你还可以选择其他流行的实现方式,比如使用现有的XML序列化包(如JAXB或XStream)来创建代表对象的TextMessage

为了适应那些无法在转换器类中通用封装的消息属性、头部(headers)和正文的设置,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.supportconverter.MessageConverter用于处理JMS消息类型,负责将消息即时转换为jakarta.jms.TextMessagejakarta.jms.BytesMessage等格式。对于支持通用消息负载的契约(contract),请使用org.springframework.messaging.converter.MessageConverterJmsMessagingTemplate结合,或者更推荐的是使用JmsClient作为核心代理。

JmsTemplate 上使用 SessionCallbackProducerCallback

虽然发送操作涵盖了多种常见的使用场景,但有时你可能希望对JMS SessionMessageProducer执行多个操作。SessionCallbackProducerCallback分别用于暴露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的Messageorg.springframework.messaging.core.MessagePostProcessor可以在JmsClient上配置后实现这一功能。它将用于通过sendsendAndReceive方法发出的所有消息。

以下是一个拦截器向所有出站消息添加“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();
}
}
}