消息隊列學習-ActiveMQ(四)
8 SpringBoot整合ActiveMQ
8.1 隊列(Queue)
8.1.1 隊列生產者
- 新建Maven工程並設置包名類名
工程名:boot_mq_produce
包名:com.sky.boot.activemq - 配置POM文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath />
</parent>
<groupId>com.sky.boot.activemq</groupId>
<artifactId>boot_mq_produce</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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-activemq</artifactId>
<version>2.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 配置yml文件
server:
port: 7777
spring:
activemq:
broker-url: tcp://192.168.188.131:61616
user: admin
password: admin
jms:
pub-sub-domain: false # false = Queue(默認) true = Topic
# 自己定義隊列名稱
myqueue: boot-active-queue
- 配置bean
@Component
@EnableJms
public class ConfigBean {
@Value("${myqueue}")
private String myQueue;
@Bean
public Queue queue(){
return new ActiveMQQueue(myQueue);
}
}
- Queue_Producer
@Component
public class Queue_Produce {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Autowired
private Queue queue;
public void produceMsg(){
jmsMessagingTemplate.convertAndSend(queue, "*****:"
+ UUID.randomUUID().toString().substring(0, 6));
}
}
- 主啓動類
@SpringBootApplication
public class MainAppProduce {
public static void main(String[] args) {
SpringApplication.run(MainAppProduce.class);
}
}
- 測試單元
@SpringBootTest(classes = MainAppProduce.class)
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class TestActiveMQ {
@Resource
private Queue_Produce queue_produce;
@Test
public void testSend() throws Exception{
queue_produce.produceMsg();
}
}
執行後,結果如下:
新需求:要求每隔3秒鐘,往MQ推送消息
- 修改Queue_Produce
@Scheduled(fixedDelay = 3000L)
public void produceMsgScheduled(){
jmsMessagingTemplate.convertAndSend(queue, "**scheduled:"
+ UUID.randomUUID().toString().substring(0, 6));
System.out.println("***** produceMsgScheduled send ok");
}
- 修改主啓動類的MainAppProduce
@SpringBootApplication
@EnableScheduling
public class MainAppProduce {
public static void main(String[] args) {
SpringApplication.run(MainAppProduce.class, args);
}
}
直接開啓主啓動類,間隔發送消息
8.1.2 隊列消費者
- 新建Mavaen工程並設置包名類名,同上一節
- POM文件,同上一節
- Yml文件,同上一節,注意:端口改了,eg:8888
- springboot的消息監聽註解
@Component
public class Queue_Consumer {
@JmsListener(destination = "${myqueue}")
public void receive(TextMessage textMessage) throws JMSException{
System.out.println("****消費者收到消息:"+textMessage.getText());
}
}
執行主方法後:
8.2 主題發佈訂閱(Topic)
8.2.1 Topic生產者
- 新建Maven工程並設置包名類名:略
- POM文件:略
- Yml文件
server:
port: 6666
spring:
activemq:
broker-url: tcp://192.168.188.131:61616
user: admin
password: admin
jms:
pub-sub-domain: true # false = Queue(默認) true = Topic
# 自己定義隊列名稱
myTopic: boot-active-topic
- 配置bean
@Component
public class ConfigBean {
@Value("${myTopic}")
private String topicName;
@Bean
public Topic topic(){
return new ActiveMQTopic(topicName);
}
}
- Topic_Producer
@Component
public class Topic_Producer {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Autowired
private Topic topic;
@Scheduled(fixedDelay = 3000L)
public void produceTopic(){
jmsMessagingTemplate.convertAndSend(topic, "主題消息:"
+ UUID.randomUUID().toString().substring(0, 6));
}
}
- 主啓動類
@SpringBootApplication
@EnableScheduling
public class BootMqToppicProducerApplication {
public static void main(String[] args) {
SpringApplication.run(BootMqToppicProducerApplication.class, args);
}
}
先啓動消費者,後啓動生產者
8.2.2 Topic消費者
- 新建Maven工程並設置包名類名:略
- POM文件:略
- Yml文件
server:
port: 5555 # 啓動第二個時,改成5566
spring:
activemq:
broker-url: tcp://192.168.188.131:61616
user: admin
password: admin
jms:
pub-sub-domain: true # false = Queue(默認) true = Topic
# 自己定義隊列名稱
myTopic: boot-active-topic
- Topic_Consumer
@Component
public class Topic_Consumer {
@JmsListener(destination = "${myTopic}")
public void receive(TextMessage textMessage) throws JMSException {
System.out.println("****消費者收到主題消息:"+textMessage.getText());
}
}
- 主啓動類
@SpringBootApplication
public class BootMqTopicConsumerApplication5555 {
public static void main(String[] args) {
SpringApplication.run(BootMqTopicConsumerApplication5555.class,
args);
}
}
9 ActiveMQ的傳輸協議
9.1 面試題
- 默認的61616端口如何更改
- 你生產上的連接協議如何配置的?使用tcp嗎?
9.2 官網
http://activemq.apache.org/configuring-version-5-transports.html
9.3 是什麼
ActiveMQ支持的client-broker通訊協議有:TVP、NIO、UDP、SSL、Http(s)、VM。
其中配置Transport Connector的文件在ActiveMQ安裝目錄的conf/activemq.xml中的標籤之內。
見下圖實際配置:
在上文給出的配置信息中,
URI描述信息的頭部都是採用協議名稱:例如
描述amqp協議的監聽端口時,採用的URI描述格式爲“amqp://······”;
描述Stomp協議的監聽端口時,採用URI描述格式爲“stomp://······”;
唯獨在進行openwire協議描述時,URI頭卻採用的“tcp://······”。這是因爲ActiveMQ中默認的消息協議就是openwire
9.4 有哪些
注意:前兩個較爲重要,其餘瞭解即可
9.4.1 Transmission Control Protocol(TCP)默認
- 這是默認的Broker配置,TCP的Client監聽端口61616
- 在網絡傳輸數據前,必須要先序列化數據,消息是通過一個叫wire protocol的來序列化成字節流。
- TCP連接的URI形式如:tcp://HostName:port?key=value&key=value,後面的參數是可選的。
- TCP傳輸的的優點:
(4.1)TCP協議傳輸可靠性高,穩定性強
(4.2)高效率:字節流方式傳遞,效率很高
(4.3)有效性、可用性:應用廣泛,支持任何平臺 - 關於Transport協議的可選配置參數可以參考官網: TCP詳情
9.4.2 New I/O API Protocol(NIO)
- NIO協議和TCP協議類似,但NIO更側重於底層的訪問操作。它允許開發人員對同一資源可有更多的client調用和服務器端有更多的負載。
- 適合使用NIO協議的場景:
(2.1)可能有大量的Client去連接到Broker上,一般情況下,大量的Client去連接Broker是被操作系統的線程所限制的。因此,NIO的實現比TCP需要更少的線程去運行,所以建議使用NIO協議。
(2.2)可能對於Broker有一個很遲鈍的網絡傳輸,NIO比TCP提供更好的性能。 - NIO連接的URI形式:nio://hostname:port?key=value&key=value
- 關於Transport協議的可選配置參數可以參考官網: NIO詳情
9.4.3 AMQP協議
Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標準高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。基於此協議的客戶端與消息中間件可傳遞消息,並不受客戶端/中間件不同產品,不同開發語言等條件限制。
9.4.4 Stomp協議
STOP,Streaming Text Orientation Message Protocol,是流文本定向消息協議,是一種爲MOM(Message Oriented Middleware,面向消息中間件)設計的簡單文本協議。
9.4.5 Secure Sockets Layer Protocol(SSL)
9.4.6 MQTT協議
MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是IBM開發的一個即時通訊協議,有可能成爲物聯網的重要組成部分。該協議支持所有平臺,幾乎可以把所有聯網物品和外部連接起來,被用來當作傳感器和致動器(比如通過Twitter讓房屋聯網)的通信協議。
擴展Github:https://github.com/fusesource/mqtt-client
9.4.7 WS協議(websocket)
9.4.8 小總結
9.5 NIO案例演示
9.5.1 修改配置文件
在transportConnectors
裏添加
<transportConnector name="nio" uri="nio://0.0.0.0:61618?trace=true" />
記得重啓activemq
9.5.2 生產和消費兩端協議代碼修改
都只改動這兩行即可
private static final String ActiveMQ_URL = "nio://192.168.188.131:61618";
private static final String QUEUE_NAME = "Protocol";
運行結果與前面一樣,略。
9.6 nio案例演示增強
問題:URI格式以"nio"開頭,代表這個端口使用TCP協議爲基礎的NIO網絡模型。
但是這樣的設置方式,只能使這個端口支持Openwire協議。
我們怎麼能夠讓這個端口既支持NIO網絡模型,又讓他支持多個協議呢?
解決:使用auto關鍵字、使用"+"符號來爲端口設置多種特性
在transportConnectors
中添加
<transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61608?maximumConnections=1000&wireFormat.maxFrameSize=104857600&org.apache.activemq.transport.nio.SelectorManager.corePoolSize=20&org.apache.activemq.transport.nio.SelectorManager.maximumPoolSize=50"/>
重啓activeMQ後,