本文主要對ActiveMQ應用場景及應用實例進行了總結,本文源碼已上傳github, 鏈接見文末。
ActiveMQ簡介
1.java消息服務:
不同系統之間的信息交換,是我們開發中比較常見的場景,比如系統A要把數據發送給系統B,這個問題我們應該如何去處理? 1999年,原來的SUN公司領銜提出了一種面向消息的中間件服務–JMS規範(標準);常用的幾種信息交互技術(httpClient、hessian、dubbo、jms、webservice 五種).
2.JMS概述:
JMS即Java消息服務(Java Message Service的簡稱),是Java EE 的標準/規範之一。這種規範(標準)指出:消息的發送應該是異步的、非阻塞的。也就是說消息的發送者發送完消息後就直接返回了,不需要等待接收者返回後才能返回,發送者和接收者可以說是互不影響。所以這種規範(標準)能夠減輕或消除系統瓶頸,實現系統之間去除耦合,提高系統的整體可伸縮性和靈活性。JMS只是Java EE中定義的一組標準API,它自身並不是一個消息服務系統,它是消息傳送服務的一個抽象,也就是說它定義了消息傳送的接口而並沒有具體實現。
3.ActiveMQ概述:
JMS只是消息服務的一組規範和接口,並沒有具體的實現,而ActiveMQ就是JMS規範的具體實現;它是Apache下的一個項目,採用Java語言開發;是一款非常流行的開源消息服務器.
4.應用場景
(1)異步處理
如下圖,用戶註冊後,直接響應,郵件和短信發送通過消息隊列異步處理。
對比下圖,縮短了響應時間,增加了系統QPS
(2)應用解耦
如下圖,應用消息隊列後,庫存系統不能正常使用,也不直接影響訂單系統。
-
訂單系統:用戶下單後,訂單系統完成持久化處理,將消息寫入消息隊列,返回用戶訂單下單成功
-
庫存系統:訂閱下單的消息,採用拉/推的方式,獲取下單信息,庫存系統根據下單信息,進行庫存操作
對比下圖:傳統模式下,庫存系統一斷無法正常使用,訂單系統也將無法正常使用。
(3)流量消峯
如下圖,一個典型應用場景:秒殺活動,一般會因爲流量過大,導致流量暴增,應用掛掉。爲解決這個問題,一般需要在應用前端加入消息隊列。這樣,用戶的請求,服務器接收後,首先寫入消息隊列。
這樣做有如下好處:
- 可以控制活動的人數:假如消息隊列長度超過最大數量,則直接拋棄用戶請求或跳轉到錯誤頁面
- 可以緩解短時間內高流量壓垮應用:秒殺業務根據消息隊列中的請求信息,再做後續處理
(4)其他場景
其他的場景還有:日誌處理,消息通訊等。
ActiveMQ安裝配置
1.下載安裝
本文介紹Mac OS下安裝
(1)推薦方式:通過brew安裝ActiveMQ
$ brew install activemq
安裝完後,通過下列命令查看版本來確定是否安裝成功:
$activemq --version
(2)也可自行下載解壓安裝:
下載地址:http://activemq.apache.org/components/classic/download/
注意mac下自行解壓安裝後啓動方式是:
// 即所有命令要在 active安裝目錄/bin/macosx下執行
cd /usr/local/apache-activemq-5.15.9/bin/macosx
./activemq start
2.啓動activeMQ服務
activemq start
顯示:Running ActiveMQ Broker… 表示啓動成功
訪問地址:http://localhost:8161/admin/
默認賬號:admin / admin
默認端口:8161 (可自行修改/usr/local/apache-activemq-5.15.9/conf/jetty.xml)
3.ActiveMQ常用命令
Tasks:
browse - Display selected messages in a specified destination.
bstat - Performs a predefined query that displays useful statistics regarding the specified broker
consumer - Receives messages from the broker
create - Creates a runnable broker instance in the specified path.
decrypt - Decrypts given text
dstat - Performs a predefined query that displays useful tabular statistics regarding the specified destination type
encrypt - Encrypts given text
export - Exports a stopped brokers data files to an archive file
list - Lists all available brokers in the specified JMX context
producer - Sends messages to the broker
purge - Delete selected destination's messages that matches the message selector
query - Display selected broker component's attributes and statistics.
start - Creates and starts a broker using a configuration file, or a broker URI.
stop - Stops a running broker specified by the broker name.
Task Options (Options specific to each task):
--extdir <dir> - Add the jar files in the directory to the classpath.
--version - Display the version information.
-h,-?,--help - Display this help information. To display task specific help, use Main [task] -h,-?,--help
ActiveMQ之Hello World 實例
不知從什麼時候起,漸漸習慣這種瞭解基本的理論後直接快速上手一個hello World實例~~ 不過,這確實是現學現用的一個好方法,但是有時間的話,還是覺得要看看書系統地瞭解一下,這樣,遇到了新問題,也有跡可循。
1.啓動activemq訪問:http://localhost:8161/admin/
點擊queues如圖:此時消息隊列爲空
2.新建maven項目
添加mq依賴:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>${activemq.version}</version>
</dependency>
最終pom.xml
<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>
<groupId>com.leon</groupId>
<artifactId>activemq-helloworld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>activemq-helloworld</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<activemq.version>5.15.9</activemq.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-all -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>${activemq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.編寫消息生產者與消費者代碼
最終目錄結構如下:
(1)Const.java :常量類
package com.leon.activemq_helloworld;
/**常量類
*
* @author leon
*
*/
public interface Const {
String MQ_DISTINATION_NAME = "mq_demo_queue";
}
(2)Producer.java:生產者
package com.leon.activemq_helloworld;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 生產者
*
* @author leon
*
*/
public class Producer {
public static void send(String msg, String distinationName) throws Exception {
// 1、創建工廠連接對象,要指定ip和端口號(61616是默認的openwrite端口,在conf/activemq.xml裏配置)
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
// 2、使用連接工廠創建一個連接對象
Connection connection = connectionFactory.createConnection();
// 3、開啓連接
connection.start();
// 4、使用連接對象創建會話(session)對象
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5、使用會話對象創建目標對象,分爲queue(p2p:一對一)和topic(發佈訂閱:一對多)
Queue queue = session.createQueue(distinationName);
// 6、使用會話對象創建消息生產者對象
MessageProducer producer = session.createProducer(queue);
// 7、使用會話對象創建一個消息對象
TextMessage textMessage = session.createTextMessage(msg);
// 8、發送消息
producer.send(textMessage);
// 9、關閉資源
producer.close();
session.close();
connection.close();
}
public static void main(String[] args) {
try {
send("hello world!", Const.MQ_DISTINATION_NAME);
System.out.println("消息已發送");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(3)Consumer.java:消費者
package com.leon.activemq_helloworld;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消費者
*
* @author leon
*
*/
public class Consumer {
public static void cust(String distinationName) throws Exception {
// 1、創建工廠連接對象,要指定ip和端口號(61616是默認的openwrite端口,在conf/activemq.xml裏配置)
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
// 2、使用連接工廠創建一個連接對象
Connection connection = connectionFactory.createConnection();
// 3、開啓連接
connection.start();
// 4、使用連接對象創建會話(session)對象
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 5、使用會話對象創建目標對象,分爲queue(p2p:一對一)和topic(發佈訂閱:一對多)
Queue queue = session.createQueue(distinationName);
// 6、使用會話對象創建消費者對象
MessageConsumer consumer = session.createConsumer(queue);
// 7、向消費者對象中設置一個messageListener對象,用來監聽和接收消息
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("接收到文本消息:");
System.out.println(textMessage.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
// 8、保持程序等待接收消息
System.in.read();
// 9、關閉資源
consumer.close();
session.close();
connection.close();
}
public static void main(String[] args) {
try {
cust(Const.MQ_DISTINATION_NAME);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(4)模擬消息隊列p2p過程
a.執行Producer.java的main(): 生產者發佈消息 -> ActiveMQ消息隊列
訪問:http://localhost:8161/admin/ :點擊queues選項卡,發現新增了一條消息。
此時,未發送的消息:消費者數量:入隊:出隊 = 1:0:1:0
b.執行Consumer.java的main(): 消費者接收消息 <- ActiveMQ消息隊列
後臺打印:
訪問:http://localhost:8161/admin/ :點擊queues選項卡,發現新增了一位消費者,未發送消息減少了一條,出隊數量增加了1。
此時,未發送的消息:消費者數量:入隊:出隊 = 0:1:1:1
(5)模擬消息隊列發佈訂閱過程
同上,不過要先執行訂閱者代碼,再執行發佈者代碼,這樣訂閱者才能接受到發佈者發佈的第一條消息,詳情參考本文源碼:https://github.com/leon2016/activemq-helloworld.git
其實,就是將
Queue queue = session.createQueue(distinationName);
改爲
Topic topic = session.createTopic(distinationName);
\---- 未完待續----
TODO 總結activemq與spring整合應用實例。
源碼
本文源碼:
activemq-helloworld :https://github.com/leon2016/activemq-helloworld.git
參考文獻:
activemq官方命令行手冊
https://www.cnblogs.com/cyfonly/p/6380860.html
https://blog.csdn.net/qq_29963323/article/details/79728581
http://www.uml.org.cn/zjjs/201802111.asp