概述
Spring 提供了一个简化 JMS API 使用的集成框架。
本教程将介绍此类集成的基本概念。
2. Maven 依赖
为了在应用中使用 Spring JMS,我们需要在 pom.xml
中添加必要的依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
您可以在此处找到最新版本的依赖项:https://mvnrepository.com/artifact/org.springframework/spring-jms
3. JmsTemplate
类
JmsTemplate
类负责在发送或同步接收消息时创建和释放资源。
因此,使用此 JmsTemplate
的类只需要实现方法定义中指定的回调接口即可。
从 Spring 4.1 开始,JmsMessagingTemplate
基于 JmsTemplate
构建,提供了与消息抽象(org.springframework.messaging.Message
)的集成,从而允许我们以通用方式创建发送的消息。
4. 连接管理
为了连接并能够发送/接收消息,我们需要配置一个 ConnectionFactory
。
ConnectionFactory
是由管理员预先配置的 JMS 管理对象之一。客户端通过配置与 JMS 提供商建立连接。
Spring 提供了两种类型的 ConnectionFactory
:
-
SingleConnectionFactory
- 实现ConnectionFactory
接口,所有createConnection()
调用返回相同的连接,并忽略close()
调用 -
CachingConnectionFactory
- 扩展了SingleConnectionFactory
功能,并增强了对会话、MessageProducer
和MessageConsumer
的缓存
5. 目的地管理
如上所述,除了 ConnectionFactory
之外,目的地也是 JMS 管理的对象,可以从 JNDI 存储和检索。
Spring 提供了通用解析器(如 DynamicDestinationResolver
)和特定解析器(如 JndiDestinationResolver
)。
JmsTemplate
将根据我们的选择将目的地名称的解析委托给其中一个实现。
它还提供了一个名为 defaultDestination
的属性,将在不引用特定目的地的 send
和 receive
操作中使用。
6. 消息转换
没有消息转换支持,Spring JMS 就不完整了。
JmsTemplate
对于 convertAndSend()
和 receiveAndConvert()
操作的默认转换策略是 SimpleMessageConverter
类。
SimpleMessageConverter
能处理 TextMessages
、BytesMessages
、MapMessages
和 ObjectMessages
。这个类实现了 MessageConverter
接口。
除 SimpleMessageConverter
之外,Spring JMS 还提供了一些内置的 MessageConverter
类,如 MappingJackson2MessageConverter
、MarshallingMessageConverter
和 MessagingMessageConverter
。
此外,只需实现 MessageConverter
接口的 toMessage()
和 fromMessage()
方法,即可创建自定义消息转换功能。
下面是一个实现自定义 MessageConverter
的示例代码片段:
public class SampleMessageConverter implements MessageConverter {
public Object fromMessage(Message message)
throws JMSException, MessageConversionException {
//...
}
public Message toMessage(Object object, Session session)
throws JMSException, MessageConversionException {
//...
}
}
7. 示例 Spring JMS
在本节中,我们将了解如何使用 JmsTemplate
发送和接收消息。
默认的发送消息方法是 JmsTemplate.send()
。它有两个关键参数:第一个是 JMS 目的地,第二个是实现 MessageCreator
的实例。JmsTemplate
使用 MessageCreator
的回调方法 createMessage()
来构建消息。
JmsTemplate.send()
适合发送纯文本消息,但要发送自定义消息,可以使用 JmsTemplate.convertAndSend()
方法。
下面是这些方法的实现:
public class SampleJmsMessageSender {
private JmsTemplate jmsTemplate;
private Queue queue;
// setters for jmsTemplate & queue
public void simpleSend() {
jmsTemplate.send(queue, s -> s.createTextMessage("hello queue world"));
}
public void sendMessage(Employee employee) {
System.out.println("Jms Message Sender : " + employee);
Map<String, Object> map = new HashMap<>();
map.put("name", employee.getName()); map.put("age", employee.getAge());
jmsTemplate.convertAndSend(map);
}
}
以下是消息接收类,即消息驱动的 POJO(MDP)。可以看到,SampleListener
类实现了 MessageListener
接口,并提供了接口方法 onMessage()
的文本特定实现。
除了 onMessage()
方法,SampleListener
类还会调用 receiveAndConvert()
方法来接收自定义消息:
public class SampleListener implements MessageListener {
public JmsTemplate getJmsTemplate() {
return getJmsTemplate();
}
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
String msg = ((TextMessage) message).getText();
System.out.println("Message has been consumed : " + msg);
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
} else {
throw new IllegalArgumentException("Message Error");
}
}
public Employee receiveMessage() throws JMSException {
Map map = (Map) getJmsTemplate().receiveAndConvert();
return new Employee((String) map.get("name"), (Integer) map.get("age"));
}
}
我们已经了解了如何实现 MessageListener
,下面是 Spring 应用上下文中的配置:
<bean id="messageListener" class="com.baeldung.spring.jms.SampleListener" />
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destinationName" ref="IN_QUEUE"/>
<property name="messageListener" ref="messageListener" />
</bean>
DefaultMessageListenerContainer
是 Spring 提供的默认消息监听容器,还有许多其他专门的容器。
8. 使用 Java 注解的基本配置
仅需使用 @JmsListener
注解,就可以将普通 bean 的一个方法转换为 JMS 听众端点。Spring JMS 提供了许多其他注解来简化 JMS 实现。
下面是一些带有注解的示例类:
@JmsListener(destination = "myDestination")
public void SampleJmsListenerMethod(Message<Order> order) { ... }
要在一个方法上添加多个监听器,只需添加多个 @JmsListener
注解。
为了支持带有 @JmsListener
注解的方法,我们需要在其中一个配置类中添加 @EnableJms
注解:
@Configuration
@EnableJms
public class AppConfig {
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory
= new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
return factory;
}
}
9. 错误处理器
我们还可以为消息监听容器配置自定义错误处理器。
首先,实现 org.springframework.util.ErrorHandler
接口:
@Service
public class SampleJmsErrorHandler implements ErrorHandler {
// ... logger
@Override
public void handleError(Throwable t) {
LOG.warn("In default jms error handler...");
LOG.error("Error Message : {}", t.getMessage());
}
}
注意,我们重写了 handleError()
方法,它简单地记录错误消息。
然后,我们需要使用 setErrorHandler()
方法将我们的错误处理服务引用到 DefaultJmsListenerConnectionFactory
:
@Bean
public DefaultJmsListenerContainerFactorybjmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory
= new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setErrorHandler(sampleJmsErrorHandler);
return factory;
}
这样,我们配置的错误处理器现在将捕获任何未处理的异常并记录消息。
如果愿意,我们也可以通过更新 appContext.xml
中的纯文本配置来配置错误处理器:
<bean id="sampleJmsErrorHandler"
class="com.baeldung.spring.jms.SampleJmsErrorHandler" />
<bean id="jmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destinationName" value="IN_QUEUE" />
<property name="messageListener" ref="messageListener" />
<property name="errorHandler" ref="sampleJmsErrorHandler" />
</bean>
10. 总结
本文讨论了 Spring JMS 的配置和基本概念,以及用于发送和接收消息的 Spring 特有的 JmsTemplate
类。
如往常一样,代码实现可在 GitHub 项目 中找到。