Spring Boot 中 JmsClient 指南
1. 概述
Spring Framework 7.0 引進了JmsClient ,這是一個用於與 JMS 目標互動的全新流暢 API。它作為JmsTemplate的現代替代方案,提供了一種更簡潔的訊息發送方式。
在本教程中,我們將建立一個簡單的應用程序,該應用程式透過JmsClient發送訊息,並使用@JmsListener接收訊息。此外,我們還將設定一個自訂的MessageConverter來處理 JSON 序列化,並討論測試策略。
2. 發送訊息
本文中的程式碼範例假設我們正在建立一個類似於 Baeldung 的部落格網站的後端。我們使用 ActiveMQ Artemis 作為 JMS 代理。
讓我們從一個簡單的docker-compose.yml開始,在本地啟動它:
services:
activemq:
image: apache/activemq-artemis:2.37.0
container_name: activemq-artemis
ports:
- "61616:61616" # JMS
- "8161:8161" # Web Console
environment:
- ARTEMIS_USER=admin
- ARTEMIS_PASSWORD=admin
然後,我們可以將spring-boot-starter-activemq依賴項新增到pom.xml中:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
有了這個依賴項, Spring Boot 會實例化一個JmsClient bean 並將其加入到應用程式上下文中。
讓我們把這個客戶端注入到其中一個元件中,並使用它來向articles-queue發送訊息:
@Component
class ArticlePublisher {
private final JmsClient jmsClient;
// constructor, logger
public void publish(String title, String author) {
var article = new Article(title, author);
log.info("Publishing article: {}", article);
jmsClient.destination("articles-queue")
.send(article);
}
record Article(String title, String author) {
}
}
此外,我們在application.yml中配置與 ActiveMQ Artemis 代理程式的連線:
spring:
artemis:
mode: native
broker-url: tcp://localhost:61616
user: admin
password: admin
這樣,我們就快完成了!最後需要配置的就是訊息序列化的方法。
3. 訊息轉換器
預設情況下,Spring JMS 使用SimpleMessageConverter來處理String 、 byte[]和Map 。要將 POJO(例如Article記錄)作為 JSON 傳送,我們需要註冊一個自訂的MessageConverter 。
MessageConverter介面有兩個方法:一個用於將 POJO 轉換為 JMS Message ,另一個用於反向轉換。在本實作中,我們將這兩個方法都委託給了 Jackson 的JsonMapper :
@Component
class JsonMessageConverter implements MessageConverter {
private final JsonMapper jsonMapper = JsonMapper.builder().build();
@Override
@SneakyThrows
public Message toMessage(Object object, Session session)
throws JMSException, MessageConversionException {
String json = jsonMapper.writeValueAsString(object);
TextMessage msg = session.createTextMessage(json);
msg.setStringProperty("_type", object.getClass().getName());
return msg;
}
@Override
@SneakyThrows
public Object fromMessage(Message message)
throws JMSException, MessageConversionException {
if (message instanceof TextMessage msg) {
var clazz = Class.forName(msg.getStringProperty("_type"));
return jsonMapper.readValue(msg.getText(), clazz);
}
throw new MessageConversionException("Message is not of type TextMessage");
}
}
當我們將物件序列化為 JSON TextMessage時,我們也會將完全限定類別名稱儲存在_type屬性中。在反序列化過程中,我們會讀取該屬性以重建正確的類型。
就是這樣! Spring Boot 偵測到MessageConverter bean 並自動將其連接到JmsTemplate 、 JmsClient和@JmsListener容器中。
4. 消費消息
此時, Spring會自動執行下列幾個操作:
- 檢測到
@JmsListener註解 - 建立一個連接到代理的訊息監聽器容器
- 輪詢隊列
- 針對每個傳入訊息呼叫該方法,並將反序列化的 POJO 直接作為方法參數傳遞。
讓我們使用此註解建立一個ArticleListener元件,並從articles-queue中消費訊息:
@Component
class ArticleListener {
private List<Article> receivedArticles = new CopyOnWriteArrayList<>();
// getter, logger
@JmsListener(destination = "articles-queue")
void onArticleReceived(ArticlePublisher.Article article) {
log.info("Received article: {}", article);
receivedArticles.add(article);
}
}
最後,讓我們透過整合測試將所有內容整合起來。具體來說,我們使用Testcontainers啟動一個真實的 ActiveMQ Artemis 代理,並驗證完整的端到端流程:
@Testcontainers
@SpringBootTest(classes = SampleApplication.class)
class ArticleListenerLiveTest {
@Container
static ArtemisContainer activeMq = new ArtemisContainer(
DockerImageName.parse("apache/activemq-artemis:2.37.0"))
.withUser("admin")
.withPassword("admin");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.artemis.broker-url", activeMq::getBrokerUrl);
}
@Autowired
ArticlePublisher articlePublisher;
@Autowired
ArticleListener articleListener;
@Test
void shouldReceivePublishedArticle() {
articlePublisher.publish("Foo", "John Doe");
articlePublisher.publish("Bar", "Jane Doe");
await().untilAsserted(() ->
assertThat(articleListener.getReceivedArticles())
.map(Article::title)
.containsExactly("Foo", "Bar"));
}
}
正如我們所看到的,該測試使用ArticlePublisher發送兩篇文章,然後斷言這兩篇文章最終都被ArticleListener接收。
5. 結論
在本文中,我們探討了 Spring 7.0 中用於發送 JMS 訊息的新流暢 API JmsClient以及用於消費這些訊息的@JmsListener 。
在實務中,我們也介紹如何連接自訂MessageConverter來處理 JSON 序列化,並透過Testcontainers整合測試驗證了整個流程。
和往常一樣,所有程式碼範例都可以 在 GitHub 上找到。