前言
安裝完RabbitMQ之後,我們就來了解一下RabbitMQ的管理命令。
詳情
第一條命令:幫助命令
rabbitmqctl help
第二條命令:插件管理
rabbitmq-plugins
list 插件列表,enable啓用插件,disable禁用插件,set重置插件。
管理界面
RabbitMQ使用的是AMQP的協議。
RabbitMQ的7中消息模型:
第一種消息模型-直連(SpringBoot演練)
加入依賴Jar包(Gradle)
compile('org.springframework.boot:spring-boot-starter-amqp')
封裝類:
import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import java.io.IOException; import java.util.concurrent.TimeoutException; public class MqUtil { public static Connection getConnection() throws IOException, TimeoutException { // 創建rabbitmq的連接工廠 ConnectionFactory connectionFactory = new ConnectionFactory(); // 設置主機IP connectionFactory.setHost("47.105.72.224"); // 設置端口 connectionFactory.setPort(5672); // 設置主機名 connectionFactory.setVirtualHost("/my"); // 設置訪問虛擬主機的IP和端口 connectionFactory.setUsername("rabbitmq"); connectionFactory.setPassword("rabbitmq"); return connectionFactory.newConnection(); } }
發送消息代碼:
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class Provoder { public void sendMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 參數1:隊列名稱,不存在自動創建 * 參數2:是否持久化隊列 * 參數3:exclusive 是否獨佔隊列(當前隊列只能被當前連接使用) * 參數4:autoDelete 是否需要消費完之後,刪除參數。 * 參數5:額外信息 */ channel.queueDeclare("hello",true,false,false,null); /** * 發佈消息 * 參數1:交互機 * 參數2:隊列 * 參數3:消息額外設置(MessageProperties.MINIMAL_PERSISTENT_BASIC) * 參數4:具體內容 */ channel.basicPublish("","hello",MessageProperties.MINIMAL_PERSISTENT_BASIC,"Hello World!".getBytes()); channel.close(); } }
測試Controller
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.concurrent.TimeoutException; @RestController public class TestController3 { @Autowired SendMqProvoder sendMqProvoder; @RequestMapping("/rabbitmq.do") public String event() throws IOException, TimeoutException { sendMqProvoder.sendMessage(); return "success"; } }
效果展示:
網頁訪問後的RabbitMq消息情況,rabbitmq的管理界面中就出現了Hello隊列,並且有兩條未消費的消息。
消費者:
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class Customer { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 參數1:隊列名稱,不存在自動創建 * 參數2:是否持久化隊列 * 參數3:exclusive 是否獨佔隊列(當前隊列只能被當前連接使用) * 參數4:autoDelete 是否需要消費完之後,刪除參數。 * 參數5:額外信息 */ channel.queueDeclare("hello",true,false,false,null); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume("hello",true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{ System.out.println(new String(body)); } }); //消費者需要一直監聽消息。 //channel.close(); //connection.close(); } }
測試類:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.concurrent.TimeoutException; @RestController public class TestController3 { @Autowired Provoder provoder; @Autowired Customer customer; @RequestMapping("/rabbitmq.do") public String event() throws IOException, TimeoutException { provoder.sendMessage(); return "success"; } @RequestMapping("/receive.do") public String receive() throws IOException, TimeoutException { customer.receiveMessage(); return "success"; } }
接收消息的結果:
第二種消息模型-work queue(SpringBoot演練)
1. 支持多個消費者,一個消息只能被消費一次。
2. 消息被多個消費者平均分配消費。
生產者:
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class WorkProvoder { public void sendMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 參數1:隊列名稱,不存在自動創建 * 參數2:是否持久化隊列 * 參數3:exclusive 是否獨佔隊列(當前隊列只能被當前連接使用) * 參數4:autoDelete 是否需要消費完之後,刪除參數。 * 參數5:額外信息 */ channel.queueDeclare("work",true,false,false,null); /** * 發佈消息 * 參數1:交互機 * 參數2:隊列 * 參數3:消息額外設置(MessageProperties.MINIMAL_PERSISTENT_BASIC) * 參數4:具體內容 */ for (int i = 0; i < 100; i++) { channel.basicPublish("","work",MessageProperties.MINIMAL_PERSISTENT_BASIC,(i+"Hello Work Queue!").getBytes()); } channel.close(); connection.close(); } }
消費者1
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class WorkCustomer { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 參數1:隊列名稱,不存在自動創建 * 參數2:是否持久化隊列 * 參數3:exclusive 是否獨佔隊列(當前隊列只能被當前連接使用) * 參數4:autoDelete 是否需要消費完之後,刪除參數。 * 參數5:額外信息 */ channel.queueDeclare("work",true,false,false,null); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume("work",true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-1:"+new String(body)); } }); } }
消費者2
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class WorkCustomer2 { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 參數1:隊列名稱,不存在自動創建 * 參數2:是否持久化隊列 * 參數3:exclusive 是否獨佔隊列(當前隊列只能被當前連接使用) * 參數4:autoDelete 是否需要消費完之後,刪除參數。 * 參數5:額外信息 */ channel.queueDeclare("work",true,false,false,null); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume("work",true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-2:"+new String(body)); } }); } }
測試類:
import java.io.IOException; import java.util.concurrent.TimeoutException; @RestController public class TestController4 { @Autowired WorkProvoder workProvoder; @Autowired WorkCustomer customer1; @Autowired WorkCustomer2 customer2; @RequestMapping("/workSend.do") public String workSend() throws IOException, TimeoutException { workProvoder.sendMessage(); return "success"; } @RequestMapping("/workReceive1.do") public String workReceive1() throws IOException, TimeoutException { customer1.receiveMessage(); return "success"; } @RequestMapping("/workReceive2.do") public String workReceive2() throws IOException, TimeoutException { customer2.receiveMessage(); return "success"; } }
運行結果:
現在的模式會出現消息丟失,平均分配的問題。
修改一下代碼,加入手動確認和每次消費一條消息,來保證消息的完整。
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class WorkCustomer2 { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 參數1:隊列名稱,不存在自動創建 * 參數2:是否持久化隊列 * 參數3:exclusive 是否獨佔隊列(當前隊列只能被當前連接使用) * 參數4:autoDelete 是否需要消費完之後,刪除參數。 * 參數5:額外信息 */ channel.queueDeclare("work",true,false,false,null); // 一次處理一個 channel.basicQos(1); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume("work",false,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-2:"+new String(body)); // 傳一個標記確認消息。 channel.basicAck(envelope.getDeliveryTag(),false); } }); } }
第三種消息模型-廣播(fanout)
生產者:
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class FanProvider { public void sendMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 設置交換機 * 參數1:交換機的名字(自取)。 * 參數2:交換機類型:fanout:就是廣播。 */ channel.exchangeDeclare("exchange1","fanout"); /** * 發佈消息 * 參數1:交互機 * 參數2:隊列 * 參數3:消息額外設置(MessageProperties.MINIMAL_PERSISTENT_BASIC:消息持久化) * 參數4:具體內容 */ for (int i = 0; i < 100; i++) { channel.basicPublish("exchange1","",MessageProperties.MINIMAL_PERSISTENT_BASIC,(i+"Hello Fan Queue!").getBytes()); } channel.close(); connection.close(); } }
消費者:
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class FanCustomer { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 綁定交換機 * 參數1:交換機名 * 參數2:交換機類型 */ channel.exchangeDeclare("exchange1","fanout"); /********* 創建一個臨時隊列 *********/ String queue = channel.queueDeclare().getQueue(); /********* 綁定交換機和隊列 *********/ channel.queueBind(queue,"exchange1",""); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume(queue,true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-1:"+new String(body)); } }); } }
運行結果:
兩個消費者都能消費到消息。
第四種消息模型-訂閱(Routing):實現不同的人去訂閱不同的消息。
生產者:
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class DirectProvider { public void sendMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 設置交換機 * 參數1:交換機的名字(自取)。 * 參數2:交換機類型:direct:路由模式。 */ channel.exchangeDeclare("logs","direct"); /******* 設置路由key ******/ String routingKey = "info"; String routingKey1 = "warn"; /** * 發佈消息 * 參數1:交互機 * 參數2:隊列 * 參數3:消息額外設置(MessageProperties.MINIMAL_PERSISTENT_BASIC:消息持久化) * 參數4:具體內容 */ channel.basicPublish("logs",routingKey,MessageProperties.MINIMAL_PERSISTENT_BASIC,(routingKey+":Hello Fan Queue!").getBytes()); channel.basicPublish("logs",routingKey1,MessageProperties.MINIMAL_PERSISTENT_BASIC,(routingKey1+":Hello Fan Queue!").getBytes()); channel.basicPublish("logs",routingKey1,MessageProperties.MINIMAL_PERSISTENT_BASIC,(routingKey1+":Hello Fan Queue!").getBytes()); channel.close(); connection.close(); } }
消費者:
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class DirectCustomer { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 綁定交換機 * 參數1:交換機名 * 參數2:交換機類型 */ channel.exchangeDeclare("logs","direct"); /********* 創建一個臨時隊列 *********/ String queue = channel.queueDeclare().getQueue(); /********* 綁定交換機和隊列和路由key *********/ channel.queueBind(queue,"logs","info"); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume(queue,true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-1:"+new String(body)); } }); } }
運行結果:
第五種消息模型-動態訂閱(Topic):實現不同的人去訂閱不同的消息,支持設置通配符。
* 匹配任意一個單詞。 *.rabbitmq
# 匹配多個任意單詞。 user.#
生產者:
import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.MessageProperties; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class TopicProvider { public void sendMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 設置交換機 * 參數1:交換機的名字(自取)。 * 參數2:交換機類型:topic:動態路由模式。 */ channel.exchangeDeclare("topic_logs","topic"); /******* 設置路由key ******/ String routingKey = "user.info"; String routingKey1 = "user.warn"; /** * 發佈消息 * 參數1:交互機 * 參數2:隊列 * 參數3:消息額外設置(MessageProperties.MINIMAL_PERSISTENT_BASIC:消息持久化) * 參數4:具體內容 */ channel.basicPublish("topic_logs",routingKey,MessageProperties.MINIMAL_PERSISTENT_BASIC,(routingKey+":Hello Topic Queue!").getBytes()); channel.basicPublish("topic_logs",routingKey1,MessageProperties.MINIMAL_PERSISTENT_BASIC,(routingKey1+":Hello Topic Queue!").getBytes()); channel.close(); connection.close(); } }
消費者1:
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class TopicCustomer { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 綁定交換機 * 參數1:交換機名 * 參數2:交換機類型 */ channel.exchangeDeclare("topic_logs","topic"); /********* 創建一個臨時隊列 *********/ String queue = channel.queueDeclare().getQueue(); /********* 綁定交換機和隊列和路由key *********/ channel.queueBind(queue,"topic_logs","*.info"); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume(queue,true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-1:"+new String(body)); } }); } }
消費者2:
import com.rabbitmq.client.*; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.concurrent.TimeoutException; @Component public class TopicCustomer1 { public void receiveMessage() throws IOException, TimeoutException { Connection connection = MqUtil.getConnection(); // 創建MQ渠道 Channel channel = connection.createChannel(); /** * 綁定交換機 * 參數1:交換機名 * 參數2:交換機類型 */ channel.exchangeDeclare("topic_logs","topic"); /********* 創建一個臨時隊列 *********/ String queue = channel.queueDeclare().getQueue(); /********* 綁定交換機和隊列和路由key *********/ channel.queueBind(queue,"topic_logs","user.*"); /** * queue 隊列名稱 * autoAck 開啓消息自動確認機制 * callback 消費消息的回調函數 */ channel.basicConsume(queue,true,new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException{ System.out.println("消費者-2:"+new String(body)); } }); } }
運行結果:
第六種通道協議(RPC)略。
第7種消息模型-發佈確認模型 略。
總結
1. rabbitmq 目前支持6中消息模型,一種通道協議。
2. rabbitmq 消息支持隊列和消息持久化
3. 結構:生產者,消費者,隊列,交換機,虛擬主機。
4. 消息確認機制,默認平均分配給每一個消費者。