目錄
ActiveMQ 5.15.4 集成 Spring Boot 2.0.3
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
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 服務。測試運行: