一、基於docker安裝(Centos下)
1、查詢一下鏡像庫
docker search rabbitmq:management
2、拉取鏡像,並查看本地是否存在
docker pull rabbitmq:management
3、啓動rabbitmq,這裏開啓兩個端口映射,5672是rabbitmq默認的客戶端連接端口,15672是web管理界面的端口。-d 是後臺運行,--name 是給容器取別名便於後面查找,最後是鏡像id。啓動後查看運行狀態
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq db322a6c3b84
二、rabbitMQ管理
1、正確安裝之後,訪問管理界面,地址是ip:15672,會出現該界面,默認用guest/guest可以登錄
三、代碼連接(爲了方便測試,生產消費端都寫在一個文件,這樣不好,真正使用請自行分離。)
調試過程中遇到一個問題(received 'fanout' but current is 'direct'。。。。。),由於我是用的docker部署的rabbitmq,解決方法如下:
#進入該容器
docker exec -it f6ccd6482b3a /bin/bash
#查看隊列
rabbitmqctl list_queues
#停止
rabbitmqctl stop_app
#清除數據
rabbitmqctl reset
#啓動
rabbitmqctl start_app
1、單發送單隊列單接收(simple 簡單模式),一個發送一個接收
public class RabbitmqSimple {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String QUEUE_NAME = "queue_name";
public static void main(String[] args) throws Exception{
producer();
consumer();
}
//生產者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//創建持久化、非自動刪除的隊列
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
String message = "project_start";
System.out.println("發送消息");
//發送消息
channel.basicPublish(
"",
QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
channel.close();
connection.close();
}
//消費者
public static void consumer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//客戶端最多接受未被ack的消息個數
channel.basicQos(50);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示該消息已經被消費
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(QUEUE_NAME,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
// channel.basicConsume(QUEUE_NAME,true,defaultConsumer);//自動模式,消費者獲取消息後服務端自動標記爲成功消費
TimeUnit.SECONDS.sleep(5);
channel.close();
connection.close();
/**另一種方式獲取,但方法已經不推薦**/
// QueueingConsumer consumer = new QueueingConsumer(channel);
// channel.basicConsume(QUEUE_NAME,consumer);
// while (true){
// QueueingConsumer.Delivery delivery = consumer.nextDelivery();
// System.out.println(new String(delivery.getBody()));
// }
/**另一種方式獲取,但方法已經不推薦**/
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
2、單發送單隊列多接收(work,工作模式),一個發送多個端一起處理消息
public class RabbitmqWork {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String QUEUE_NAME = "queue_name";
public static void main(String[] args) throws Exception{
producer();
consumer(1);
consumer(2);
}
//生產者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//創建持久化、非自動刪除的隊列
channel.queueDeclare(QUEUE_NAME,true,false,false,null);
System.out.println("發送消息");
for(int i=0;i<10;i++){
//發送消息
String message = "project_start:" + i;
channel.basicPublish(
"",
QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
}
channel.close();
connection.close();
}
//消費者
public static void consumer(int cons) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//客戶端最多接受未被ack的消息個數,現在設置1,同一時刻只接收一個,處理完返回成功再繼續接收
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(cons + "消費者:"+ new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示該消息已經被消費
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(QUEUE_NAME,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
TimeUnit.SECONDS.sleep(5);
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
3、單發送多隊列多接收(Publish/Subscribe 發佈、訂閱模式),假如每個消費者一個隊列則可實現收到相同信息(廣播)
public class RabbitmqPublish {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String TYPE = "fanout";
private static final String EXCHANGE_NAME = "exchange_name";
private static final String QUEUE_NAME = "queue_name";
private static final String QUEUE_NAME2 = "queue_name2";
public static void main(String[] args) throws Exception{
producer();
consumer(QUEUE_NAME);
consumer(QUEUE_NAME2);
}
//生產者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//創建持久化、非自動刪除的交換器,Exchange有4種類型:direct(默認),fanout,topic,和headers,這裏用fanout 廣播消息,不需要使用queue
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
String message = "project_start";
System.out.println("發送消息");
//發送消息
channel.basicPublish(
EXCHANGE_NAME,
"",
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
channel.close();
connection.close();
}
//消費者
public static void consumer(String queue) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//交換機
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
//創建持久化、非自動刪除的隊列
channel.queueDeclare(queue,true,false,false,null);
//交換器和隊列進行綁定,注意這裏不同消費者交換器名字一樣,但隊列不同
channel.queueBind(queue,EXCHANGE_NAME,"");
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(queue + ":" + new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示該消息已經被消費
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queue,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
4、消費者根據不同路由key(Routing 路由模式),在第三點的基礎上把type改成direct,發送消息加了routing key
public class RabbitmqRouting {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String TYPE = "direct";
private static final String EXCHANGE_NAME = "exchange_name";
private static final String QUEUE_NAME = "queue_name";
private static final String QUEUE_NAME2 = "queue_name2";
private static final String ROUTING_KEY = "routing_key";
private static final String ROUTING_KEY2 = "routing_key2";
public static void main(String[] args) throws Exception{
producer();
consumer(QUEUE_NAME,ROUTING_KEY);
consumer(QUEUE_NAME2,ROUTING_KEY2);
}
//生產者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//創建持久化、非自動刪除的交換器,Exchange有4種類型:direct(默認),fanout,topic,和headers,這裏用fanout 廣播消息,不需要使用queue
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
String message = "project_start";
System.out.println("發送消息");
//發送消息
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
//另一個路由
String message2 = "project_start2";
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY2,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message2.getBytes()
);
channel.close();
connection.close();
}
//消費者
public static void consumer(String queue,String routing) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//交換機
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
//創建持久化、非自動刪除的隊列
channel.queueDeclare(queue,true,false,false,null);
//交換器和隊列進行綁定,注意這裏不同消費者交換器名字一樣,但隊列不同和路由key不一樣
channel.queueBind(queue,EXCHANGE_NAME,routing);
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(queue + ":" + new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示該消息已經被消費
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queue,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}
5、兩端都按通配符匹配(Topics 主題模式),在第三點的基礎上把type改成topic,發送消息的routing key去匹配binding key,比如 routing.* 這種規則,也可以用 # ,* 是匹配一個單詞,# 是匹配多個單詞
public class RabbitmqTopic {
private static final String IP = "192.168.1.60";
private static final int PORT = 5672;
private static final String USERNAME = "guest";
private static final String PASSWORD = "guest";
private static final String TYPE = "topic";
private static final String EXCHANGE_NAME = "exchange_name";
private static final String QUEUE_NAME = "queue_name";
private static final String QUEUE_NAME2 = "queue_name2";
private static final String ROUTING_KEY = "routing.key";
private static final String ROUTING_KEY2 = "routing.key2";
private static final String BINDING_KEY_COMMON = "routing.*";
public static void main(String[] args) throws Exception{
producer();
consumer(QUEUE_NAME);
consumer(QUEUE_NAME2);
}
//生產者
public static void producer() throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//創建持久化、非自動刪除的交換器,Exchange有4種類型:direct(默認),fanout,topic,和headers,這裏用fanout 廣播消息,不需要使用queue
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
System.out.println("發送消息");
//發送消息
String message = "project_start";
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes()
);
//另一個路由
String message2 = "project_start2";
channel.basicPublish(
EXCHANGE_NAME,
ROUTING_KEY2,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message2.getBytes()
);
channel.close();
connection.close();
}
//消費者
public static void consumer(String queue) throws Exception{
Connection connection = getConnection();
Channel channel = connection.createChannel();
//交換機
channel.exchangeDeclare(EXCHANGE_NAME,TYPE);
//創建持久化、非自動刪除的隊列
channel.queueDeclare(queue,true,false,false,null);
//交換器和隊列進行綁定,注意這裏不同消費者交換器名字一樣,但隊列不同,路由採用匹配方式
channel.queueBind(queue,EXCHANGE_NAME,BINDING_KEY_COMMON);
channel.basicQos(1);
Consumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(queue + ":" + new String(body));
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//表示該消息已經被消費
channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queue,false,defaultConsumer);//手動模式,消費者成功消費後服務端不會自動標記爲成功消費,需要將狀態傳回服務端手動更新
}
public static Connection getConnection() throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(IP);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
Connection connection = factory.newConnection();
return connection;
}
}