1. 概述
Spring 提供了一個 JMS 集成框架,簡化了 JMS API 的使用。
在本教程中,我們將介紹這種集成的基本概念。
2. Maven 依賴
為了在我們的應用程序中使用 Spring JMS,我們需要在 pom.xml 中添加必要的 Artifacts:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>
最新版本的該 Artifact 可以 在此處找到。
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 的功能,並增加了對 Sessions、MessageProducers 和 MessageConsumers 的緩存
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 還提供了MappingJackson2MessageConverter、MarshallingMessageConverter、MessagingMessageConverter 等其他MessageConverter 類。
此外,我們只需通過實現 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 註解。
我們需要在其中一個配置類中添加 @EnableJms 註解,以支持帶有 @JmsListener 註解的方法:
@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()方法,它只是記錄錯誤消息。
接下來,我們需要在DefaultJmsListenerConnectionFactory中使用setErrorHandler()方法引用我們的錯誤處理服務。
@Bean
public DefaultJmsListenerContainerFactorybjmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory
= new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setErrorHandler(sampleJmsErrorHandler);
return factory;
}有了這個,我們的配置錯誤處理程序將捕獲任何未處理的異常並記錄消息。
可選地,我們還可以通過更新我們的appContext.xml,使用傳統的 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 相關的 <em >JmsTemplate</em> 類,這些類用於發送和接收消息。