Spring Boot 2.0.3 集成 ActiveMQ 5.15.4 與 內嵌啓動 ActiveMQ 服務

目錄

ActiveMQ 5.15.4 集成 Spring Boot 2.0.3

pom.xml 依賴

application.yml 配置

@JmsListener 接收消息

JmsTemplate 發送消息

運行測試

內嵌啓動 ActiveMQ 服務


ActiveMQ 5.15.4 集成 Spring Boot 2.0.3

1、SpringBoot 提供了對 JMS 的支持,對主流的消息中間件如 RabbitMQ、Apache Kafka、Apache ActiveMQ 等都提供了集成。

2、參照 spring boot 官方文檔 ActiveMQ Support 即可輕鬆集成 ActiveMQ 與 Spring Boot。

3、本文演示環境:Spring Boot 2.0.3 + ActiveMQ 5.25.4 + IDEA 2018。整體結構如下 MessageConsumer 作爲消息消費者,監聽消息並打印到控制檯,MessageController 作爲控制層,用戶從頁面請求發送消息。

(單獨運行解壓的 ActiveMQ 5.15.9 作爲消息服務器)

pom.xml 依賴

1、新建 Spring Boot web 應用,pom.xml 文件內容如下:

<properties>
    <java.version>1.8</java.version>
</properties>
<dependencies>
    <!--使用 spring-boot-starter-activemq,將提供連接或嵌入activemq實例所需的依賴項-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-activemq</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

spring-boot-starter-activemq : spring boot 集成的 activemq 依賴,spring boot 2.0.3 版本集成 activemq 5.15.4 版本

spring-boot-starter-web:創建 web 應用,後續可以從瀏覽器發送消息,方便測試。

application.yml 配置

1、activemq 配置由 spring.activemq.* 屬性控制,下面簡單演示幾項:

spring:
  activemq:
    broker-url: 'tcp://localhost:61616'   #ActiveMQ服務請求地址,不寫時默認爲 tcp://localhost:61616
    in-memory: true   #默認代理 URL 是否應在內存中,默認爲 true
    pool:
      enabled: false  #是否應創建 JmsPoolConnectionFactory,而不是常規的 ConnectionFactory,默認 false
      max-connections: 50   #最大池連接數
  jms:
    cache:
      session-cache-size: 5  #會話緩存的大小(每個jms會話類型),默認爲 1

更多詳細配置參考官網:https://docs.spring.io/spring-boot/docs/2.1.6.RELEASE/reference/htmlsingle/#common-application-properties

ActiveMQProperties.java:https://github.com/spring-projects/spring-boot/blob/v2.1.6.RELEASE/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jms/activemq/ActiveMQProperties.java

@JmsListener 接收消息

1、接收消息只需要一個 @JmsListerner 註解即可,自動會監聽指定消息隊列的消息,官網傳送 Receiving a Message。

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;    
/**
 * 消息消費者
 */
@Component
public class MessageConsumer {
    /**
     * 當 jms 基礎設施存在時,任何 bean 都可以用 @JmsListener 註解創建監聽器端點,如果未定義 JmsListenerContainerFactory,則會自動配置默認值。
     * 默認情況下,默認工廠是事務性的。如果在存在 JtaTransactionManager 的基礎結構中運行,則默認情況下它與偵聽器容器相關聯
     * @param message
     */
    @JmsListener(destination = "my-queue")
    public void receiveMessage(String message) {
        System.err.println("接收到了消息: " + message);
    }
    /**
     * 可以同時監聽任意多個消息隊列,都會自動接收消息。
     * @param message
     */
    @JmsListener(destination = "my-queue2")
    public void receiveMessage2(String message) {
        System.out.println("收到消息:" + message);
    }
}

JmsTemplate 發送消息

1、JmsTemplate 對 Spring boot 支持的所有 JMS 庫提供了統一操作的 API。程序員不用再像調用原生的 ActiveMQ API 一樣去考慮打開連接、打開、關閉 Session 等操作。官網傳送 Sending a Message。

import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Destination;
/**
 * jms 消息控制層
 */
@RestController
@RequestMapping("jms")
public class MessageController {
    /**spring 的 JmsTemplate 是自動配置,可以直接注入使用,如同 JdbcTemplate 一樣,非常方便,封裝好了 API,直接調用即可*/
    @Autowired
    private JmsTemplate jmsTemplate;
    /**JmsMessagingTemplate 對 JmsTemplate 進行了封裝,都可以用來發送消息*/
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    /**請求地址:http://localhost:8080/jms/sendMessage1?message=謝三哥
     * @param message:待發送的消息
     * @return
     */
    @GetMapping("sendMessage1")
    public String sendMessage1(String message) {
        String formatMessage = messageFormat(message);
        Destination destination = new ActiveMQQueue("my-queue");/**創建消息隊列,自定義隊列名稱*/
        /**convertAndSend(D destination, Object payload):轉換與發送消息,destination:目的地,payload:待發送的消息,底層調用 send 方法
         * send(D destination, Message<?> message):發送消息,convertAndSend 方法會將原始消息加入消息頭轉換成真正能發送的消息(Message)
         * 支持發送的消息類型有:String, byte array, Map<String,?>, Serializable object.
         * 如下所示如果直接傳 jsonNodes,則會拋異常,因爲不支持 jsonNodes
         * 待發送的消息不能爲 null,也不建議爲空,否則接收端默認會拋異常
         */
        jmsTemplate.convertAndSend(destination, formatMessage);
        return formatMessage;
    }
    /**發送消息。請求地址:http://localhost:8080/jms/sendMessage2?message=張三哥
     * @param message:待發送的消息
     * @return
     */
    @GetMapping("sendMessage2")
    public String sendMessage2(String message) {
        String formatMessage = messageFormat(message);
        Destination destination = new ActiveMQQueue("my-queue2");/**創建消息隊列,自定義隊列名稱*/
        jmsMessagingTemplate.convertAndSend(destination, formatMessage);/**轉換與發送消息*/
        return formatMessage;
    }
    /**
     * 將待發送的消息先進行 json 格式化一下,便於傳輸與取值。
     *
     * @param message :用戶待發送的原始消息
     * @return :返回轉換好的 json 格式的消息
     */
    private String messageFormat(String message) {
        JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance;
        ObjectNode jsonNodes = jsonNodeFactory.objectNode();
        jsonNodes.put("message", message);//message 爲 null 時,照樣可以 put
        jsonNodes.put("status", 200);
        jsonNodes.put("timeStamp", System.currentTimeMillis());
        return jsonNodes.toString();
    }
}

運行測試

1、先啓動 ActiveMQ 消息服務器,然後啓動本應用,訪問瀏覽器地址,MessageConsumer 能接收到消息,便說明成功了。

項目源碼:https://github.com/wangmaoxiong/active_mq_2

內嵌啓動 ActiveMQ 服務

1、實際生產環境中大多還是將 ActiveMQ 單獨作爲服務器啓動,但是平時開發、測試時使用內嵌的 ActiveMQ 服務也是很方便的,就像內嵌 tomcat 服務器一樣。

2、《ActiveMQ 命令行啓動 與 嵌入式啓動》中已經介紹了 "嵌入式啓動",不過彼時是 Maven 管理的 Java SE 應用,現在是 Spring Boot web 應用。

3、仍然可以沿用此思路,使用 BrokerService API 進行內嵌啓動,在 spring boot 啓動後自動執行 brokerService.start() 啓動即可,顯然容易想到的是用 ServletContextListener 應用啓動監聽器。監聽到應用啓動後,執行 brokerService.start() 啓動內嵌的 ActiveMQ 服務。(這只是多種方式中的其中一個思路,僅供參考)

4、內嵌 ActiveMQ 服務器時,還需要再添加 activemq-kahadb-store 依賴:

<!--使用 spring-boot-starter-activemq,將提供連接或嵌入activemq實例所需的依賴項-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!--ActiveMQ 服務器內嵌啓動時,需要添加 activemq-kahadb-store,用於數據持久化-->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-kahadb-store</artifactId>
</dependency>

5、然後寫一個應用啓動監聽器,實現 ServletContextListener 即可,在應用啓動初始化方法中啓動 ActiveMQ 服務:

import org.apache.activemq.broker.BrokerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
 * 標準的 Servlet 監聽器。
 */
public class SystemListener implements ServletContextListener {
    private static final Logger logger = LoggerFactory.getLogger(SystemListener.class);
    /**
     * 應用啓動時自動執行
     * @param servletContextEvent
     */
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        try {
            logger.info("應用啓動......");
            /**設置 ActiveMQ 消息服務器用於被客戶端連接的 url 地址,實際開發中,地址應該在配置文件中可配置,不要寫死*/
            String serviceURL = "tcp://localhost:61616";
            /**BrokerService 表示 ActiveMQ 服務,每一個 BrokerService 表示一個消息服務器實例
             * 如果想啓動多個,只需要 start 多個不同端口的 BrokerService 即可*/
            BrokerService brokerService = new BrokerService();
            brokerService.setUseJmx(true);//設置是否應將代理的服務公開到jmx中。默認是 true
            brokerService.addConnector(serviceURL);//爲指定地址添加新的傳輸連接器
            /**啓動 ActiveMQ 服務,此時客戶端便可以使用提供的地址進行連接,然後發送消息過來,或者從這裏消費消息。
             * 注意:這裏內嵌啓動後,默認是沒有提供 8161 端口的 web 管理界面的,照樣能做消息中間件使用*/
            brokerService.start();
            logger.info("啓動內嵌 ActiveMQ 服務器完成......");
        } catch (Exception e) {
            logger.error("啓動內嵌 ActiveMQ 服務器失敗...");
        }
    }
    /**應用銷燬時自動執行*/
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        logger.info("應用關閉......");
    }
}

6、然後寫一個配置類註冊 servlet 容器啓動監聽器:

import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**系統配置類*/
@Configuration
public class SystemConfig {
    /**
     * 註冊 Servlet 三大組件 之  Listner
     * 添加 ServletListenerRegistrationBean ,就相當於以前在 web.xml 中配置的 <listener></listener>標籤
     */
    @Bean
    public ServletListenerRegistrationBean myListener() {
        /**ServletListenerRegistrationBean<T extends EventListener> 使用的是泛型,可以註冊常見的任意監聽器
         * 將自己的監聽器註冊進來*/
        ServletListenerRegistrationBean registrationBean =
                new ServletListenerRegistrationBean(new SystemListener());
        return registrationBean;
    }
}

7、其它代碼不用修改,現在可以關閉獨立啓動的 ActiveMQ 服務器了,使用內嵌 activeMQ 服務。測試運行:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章