前言
什麼是消息隊列?
消息是指在兩個獨立的系統間傳遞的數據,這兩個系統可以是兩臺計算機,也可以是兩個進程。
消息可以非常簡單,可以是簡單的字符串,也可以是保存了數據持久化的各種類型的文檔集合。
隊列是在消息的傳輸過程中的通道,是保存消息的容器,根據不同的情形,可以有先進先出,優先級隊列等區別 。
爲什麼要使用消息隊列?
我個人的理解是主要對業務的解耦,操作異步處理,還有流量削鋒等等問題,最終實現高性能,高可用,可伸縮和最終一致性。大家可參考這篇博客:https://blog.csdn.net/seven__________7/article/details/70225830
開始
整合準備工作:先去官網http://activemq.apache.org/activemq-5154-release.html 下載開發包,我下載的是windows版本的,得到apache-activemq-5.15.4-bin.zip
這樣一個壓縮文件,解壓後,打開bin目錄下的win32或者win64文件夾(根據自己windows版本),運行activemq.bat(請確保java環境變量無誤,否則將閃退 ),保持運行窗口,打開瀏覽器訪問http://127.0.0.1:8161/admin,輸入用戶名密碼(默認均爲admin),得到下面的消息隊列控制檯頁面,即完成準備工作。
下面開始代碼工作:
新建一個java工程,將開發包中的activemq-all-5.15.4.jar
引入項目後即可開始。
(1)使用點對點模式,不可重複消費
創建消息發佈者JMSProducer
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息發佈者
* @author zxy
*
*/
public class JMSProducer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static final String BROKERURL = ActiveMQConnection.DEFAULT_BROKER_URL;
private static final int SENDNUM = 10;
public static void main(String[] args) {
ConnectionFactory connectionFactory = null; //連接工廠
Connection connection = null; //連接
Session session = null; //會話接收或者發送消息的線程
Destination destination = null; //消息的目的地
MessageProducer messageProducer = null; //消息生產者
//實例化連接工廠
connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
try {
//通過連接工廠獲取連接
connection = connectionFactory.createConnection();
connection.start();
//Boolean.TRUE表示開啓事務
session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//創建消息隊列
destination = session.createQueue("FirstQueue1");
//創建消息生產者
messageProducer = session.createProducer(destination);
//發送消息
sendMessage(session, messageProducer);
//事務提交
session.commit();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void sendMessage(Session session, MessageProducer messageProducer){
for(int i=0;i<SENDNUM;i++){
try {
TextMessage textMessage = session.createTextMessage("ActiveMQ 發送的消息" + i);
System.out.println("發送消息:ActiveMQ發送的消息" + i);
messageProducer.send(textMessage);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
創建消息消費者JMSConsumer,兩種消費方式:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息消費者一
* 不斷從隊列出口獲取消息
* @author zxy
*
*/
public class JMSConsumer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static final String BROKERURL = ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) {
ConnectionFactory connectionFactory = null; //連接工廠
Connection connection = null; //連接
Session session = null; //會話接收或者發送消息的線程
Destination destination = null; //消息的目的地
MessageConsumer messageConsumer = null; //消息消費者
//實例化連接工廠
connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
try {
//通過連接工廠獲取連接
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//創建消息隊列
destination = session.createQueue("FirstQueue1");
//創建消息生產者
messageConsumer = session.createConsumer(destination);
while(true){
TextMessage message = (TextMessage)messageConsumer.receive(100000);
if(message != null){
System.out.println("收到的消息:" + message.getText());
}else{
break;
}
}
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息消費者二
* 通過消息監聽獲取消息
* @author Administrator
*
*/
public class JMSConsumer2 {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static final String BROKERURL = ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) {
ConnectionFactory connectionFactory = null; //連接工廠
Connection connection = null; //連接
Session session = null; //會話接收或者發送消息的線程
Destination destination = null; //消息的目的地
MessageConsumer messageConsumer = null; //消息消費者
// 實例化連接工廠
connectionFactory=new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
try {
//通過連接工廠獲取連接
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//創建消息隊列
destination = session.createQueue("FirstQueue1");
// 創建消息消費者
messageConsumer=session.createConsumer(destination);
// 註冊消息監聽
messageConsumer.setMessageListener(new Listener());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
消費方式一:
先開啓JMSProducer,再開啓JMSConsumer,消費結果如下:
消費方式二:
將JMSConsumer2複製一份重命名爲JMSConsumer3,將兩個先開啓,監聽消息發佈,然後再開啓JMSProducer,消費結果如下:
JMSConsumer2:
JMSConsumer3:
瀏覽器控制檯Queues
菜單項下可以找到如下結果,消息發佈數量與消息消費數量始終保持一致:
(2)使用發佈/訂閱模式,可重複消費
創建消息發佈者JMSProducer,與上述消息發佈者其他代碼全部一致,將創建消息隊列的代碼改動即可
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class JMSProducer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static final String BROKERURL = ActiveMQConnection.DEFAULT_BROKER_URL;
private static final int SENDNUM = 10;
public static void main(String[] args) {
ConnectionFactory connectionFactory = null; //連接工廠
Connection connection = null; //連接
Session session = null; //會話接收或者發送消息的線程
Destination destination = null; //消息的目的地
MessageProducer messageProducer = null; //消息生產者
//實例化連接工廠
connectionFactory = new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
try {
//通過連接工廠獲取連接
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//創建消息隊列
destination = session.createTopic("FirstTopic1");
//創建消息生產者
messageProducer = session.createProducer(destination);
//發送消息
sendMessage(session, messageProducer);
session.commit();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(connection != null){
try {
connection.close();
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void sendMessage(Session session, MessageProducer messageProducer){
for(int i=0;i<SENDNUM;i++){
try {
TextMessage textMessage = session.createTextMessage("ActiveMQ 發送的消息" + i);
System.out.println("發送消息:ActiveMQ發佈的消息" + i);
messageProducer.send(textMessage);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
創建消息消費者JMSConsumer,與消息發佈者代碼改動一致:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息消費者
* @author Administrator
*
*/
public class JMSConsumer {
private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
private static final String BROKERURL = ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) {
ConnectionFactory connectionFactory = null; //連接工廠
Connection connection = null; //連接
Session session = null; //會話接收或者發送消息的線程
Destination destination = null; //消息的目的地
MessageConsumer messageConsumer = null; //消息消費者
// 實例化連接工廠
connectionFactory=new ActiveMQConnectionFactory(USERNAME, PASSWORD, BROKERURL);
try {
//通過連接工廠獲取連接
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//創建消息隊列
destination = session.createTopic("FirstTopic1");
// 創建消息消費者
messageConsumer=session.createConsumer(destination);
// 註冊消息監聽
messageConsumer.setMessageListener(new Listener());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
將JMSConsumer複製一份重命名爲JMSConsumer2,將兩個先開啓,監聽消息發佈,然後再開啓JMSProducer,消費結果如下:
兩者均爲一個結果:
瀏覽器控制檯Topics
菜單項下可以找到如下結果,消息發佈了10條,卻消費了20次,即兩個消費者重複消費了消息:
總結:以上即爲所有過程,完成了ActiveMQ兩種模式小demo 的整合,如有不足,歡迎指正。