首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring 整合 ActiveMQ 完整實戰:點對點隊列與發布訂閱模型、監聽器配置、壓力測試

     編輯:Java 綜合教學

前言

本文基於 **Spring 4.1 + ActiveMQ 5.12 + Tomcat 7 + Maven** 實作完整的 JMS 整合範例,涵蓋 **Point-to-Point (Queue)** 與 **Publish/Subscribe (Topic)** 兩種模型、生產者/消費者服務、監聽器容器、REST 測試端點與壓力測試。

專案結構

src/main/java
├── com.jayce
│   ├── config
│   │   ├── WebConfig.java          # Spring MVC 配置
│   │   └── ActiveMQConfig.java     # ActiveMQ 連線工廠、Queue/Topic、JmsTemplate、ListenerContainer
│   ├── controller
│   │   └── MessageController.java  # REST 端點:發送/接收訊息
│   ├── service
│   │   ├── ProducerService.java    # 發送訊息服務
│   │   └── ConsumerService.java    # 手動接收訊息服務
│   └── listener
│       └── QueueMessageListener.java # 非同步監聽器 (實作 MessageListener)

核心配置 (ActiveMQConfig.java)

@Configuration
@EnableJms
public class ActiveMQConfig {

    @Value("${activemq.broker-url:tcp://localhost:61616}")
    private String brokerUrl;

    @Value("${activemq.user:admin}")
    private String user;

    @Value("${activemq.password:admin}")
    private String password;

    // 1. ActiveMQ 連線工廠
    @Bean
    public ActiveMQConnectionFactory amqConnectionFactory() {
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
        factory.setBrokerURL(brokerUrl);
        factory.setUserName(user);
        factory.setPassword(password);
        factory.setTrustAllPackages(true); // 允許傳遞 ObjectMessage
        return factory;
    }

    // 2. Spring 快取連線工廠 (效能關鍵)
    @Bean
    public CachingConnectionFactory connectionFactory() {
        CachingConnectionFactory factory = new CachingConnectionFactory(amqConnectionFactory());
        factory.setSessionCacheSize(100);
        return factory;
    }

    // 3. 定義 Queue (點對點)
    @Bean
    public Queue demoQueue() {
        return new ActiveMQQueue("jayce.queue.demo");
    }

    // 4. 定義 Topic (發布訂閱)
    @Bean
    public Topic demoTopic() {
        return new ActiveMQTopic("jayce.topic.demo");
    }

    // 5. JmsTemplate (Queue 操作)
    @Bean
    public JmsTemplate jmsQueueTemplate() {
        JmsTemplate template = new JmsTemplate(connectionFactory());
        template.setDefaultDestination(demoQueue());
        template.setReceiveTimeout(10000);
        template.setPubSubDomain(false); // false=Queue, true=Topic
        return template;
    }

    // 6. JmsTemplate (Topic 操作)
    @Bean
    public JmsTemplate jmsTopicTemplate() {
        JmsTemplate template = new JmsTemplate(connectionFactory());
        template.setDefaultDestination(demoTopic());
        template.setPubSubDomain(true);
        return template;
    }

    // 7. 非同步監聽器容器 (Queue)
    @Bean
    public DefaultMessageListenerContainer queueListenerContainer() {
        DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
        container.setConnectionFactory(connectionFactory());
        container.setDestination(demoQueue());
        container.setMessageListener(queueMessageListener());
        container.setConcurrency("5-10"); // 5-10 消費者執行緒
        return container;
    }

    @Bean
    public QueueMessageListener queueMessageListener() {
        return new QueueMessageListener();
    }
}

服務層實作

ProducerService.java

@Service
public class ProducerService {

    @Autowired @Qualifier("jmsQueueTemplate")
    private JmsTemplate queueTemplate;

    @Autowired @Qualifier("jmsTopicTemplate")
    private JmsTemplate topicTemplate;

    // 發送到預設 Queue
    public void sendToQueue(final String msg) {
        queueTemplate.send(session -> session.createTextMessage(msg));
    }

    // 發送到指定 Destination
    public void sendToQueue(Destination dest, final String msg) {
        queueTemplate.send(dest, session -> session.createTextMessage(msg));
    }

    // 發送到 Topic (廣播)
    public void sendToTopic(final String msg) {
        topicTemplate.send(session -> session.createTextMessage(msg));
    }
}

ConsumerService.java (手動接收)

@Service
public class ConsumerService {

    @Autowired @Qualifier("jmsQueueTemplate")
    private JmsTemplate queueTemplate;

    public TextMessage receiveFromQueue(Destination dest) {
        return (TextMessage) queueTemplate.receive(dest);
    }
}

QueueMessageListener.java (非同步監聽)

控制層 REST 端點

application.yml 配置

activemq:
  broker-url: tcp://192.168.148.128:61616
  user: admin
  password: admin

server:
  port: 8080

spring:
  jms:
    pub-sub-domain: false  # 預設 Queue

測試驗證

1. 啟動 ActiveMQ

# Linux/Mac
./bin/activemq start
# 管理主控台: https://localhost:8161/admin (admin/admin)

2. 發送訊息 (Postman/curl)

curl -X POST "https://localhost:8080/api/message/send-queue?msg=Hello%20Queue"
curl -X POST "https://localhost:8080/api/message/send-topic?msg=Hello%20Topic"

3. 觀察 ActiveMQ Web Console

  • Queues 頁籤:`jayce.queue.demo` 訊息數 +1、Dequeue 數 +1 (監聽器自動消費)。
  • Topics 頁籤:`jayce.topic.demo` 訊息數 +1、訂閱者收到。

4. 手動接收

curl "https://localhost:8080/api/message/receive-queue"

5. 監聽器自動消費驗證

發送後**無需呼叫 receive 端點**,後台日誌即顯示 `收到 Queue 訊息: ...`,證明 `DefaultMessageListenerContainer` 正常運作。

壓力測試 (Apache HttpClient)

@Test
public void stressTest() throws Exception {
    HttpClient client = HttpClients.createDefault();
    int threadCount = 20;
    int msgPerThread = 500;
    CountDownLatch latch = new CountDownLatch(threadCount);

    for (int t = 0; t < threadCount; t++) {
        new Thread(() -> {
            try {
                for (int i = 0; i < msgPerThread; i++) {
                    HttpPost post = new HttpPost("https://localhost:8080/api/message/send-queue");
                    post.setEntity(new StringEntity("msg=" + UUID.randomUUID(), ContentType.APPLICATION_FORM_URLENCODED));
                    client.execute(post);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        }).start();
    }
    latch.await();
    System.out.println("壓測完成: " + (threadCount * msgPerThread) + " 訊息");
}

觀察 ActiveMQ Enqueue/Dequeue 速率、JVM GC 情況、資料庫連線池使用率。

關鍵最佳實踐總結

實踐理由
使用 CachingConnectionFactory重用 Session/Producer,避免每次發送建立連線,效能提升 10x+
設定 ListenerContainer concurrency多執行緒並行消費,提升吞吐量
生產者用 JmsTemplate.send(MessageCreator)自動管理 Session 生命週期,異常自動回滾
啟用事務 (sessionTransacted=true)確保訊息處理與資料庫操作原子性
設定 Dead Letter Queue (DLQ)重試失敗訊息自動轉入 DLQ,避免丟失
監控 Queue 深度、消費延遲及時發現積壓、擴容消費者

結語

Spring + ActiveMQ 整合核心在於:**CachingConnectionFactory 重用連線、JmsTemplate 簡化發送/接收、DefaultMessageListenerContainer 非同步消費**。掌握 Queue/Topic 兩種模型差異、事務邊界、死信處理與監控指標,即可建構穩健的企業級訊息系統。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved