# RabbitMQ **Repository Path**: xun963/RabbitMQ ## Basic Information - **Project Name**: RabbitMQ - **Description**: No description available - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-06-12 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### **1. 消息队列解决问题** * 日志收集:系统日志不是主体逻辑,属于辅助性功能,日志系统即使挂了也不能影响主业务逻辑,所以需要单独处理; * 异步处理:对非实时性功能采用异步处理,例如系统需要发送优惠消息给客户,那么可以采用异步推送; * 异步解耦:两个系统对接,可以采用实时接口调用,也可以采用MQ中间层解耦; * 流量消费:在流量高峰时期将待处理内容发送到MQ,后台消费服务平滑处理,避免实时高峰流量造成系统崩溃,达到削峰填谷的目的; ### 2. RabbitMQ安装 * 具体可以参考网络,先安装erlang,再安装RabbitMQ:https://blog.csdn.net/hzw19920329/article/details/53156015 * 默认用户名、密码:guest ![1555119896515](README.assets/1555119896515.png) * 添加用户 ![1555119759146](README.assets/1555119759146.png) * virtual hosts管理 virtual hosts 相当于mysql 的 db ![1555120087927](README.assets/1555120087927.png) 一般以/开头,然后对用户授权 ![1555120125325](README.assets/1555120125325.png) 可以看大授权后用户有对该virtual的权限 ![1555120164045](README.assets/1555120164045.png) ### 3. RabbitMQ工作模式 #### 3.1 工作模式简述 一共6种:简单队列模式、工作队列模式、发布订阅模式、路由模式、主题模式、RPC模式 ![1555120602211](README.assets/1555120602211.png) ![1555120610824](README.assets/1555120610824.png) #### 3.2 简单队列 * 模型:一对一的模型,即一个生产者发送消息到一个队列,一个消费者监听队列进行消息消费处理![img](README.assets/Image.png)![img](data:image/png;base64,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)P:消息的生产者 ;红色:队列 ;C:消息的消费者 * 代码示例: 添加Maven依赖: ```java com.rabbitmq amqp-client 5.2.0 io.dropwizard.metrics metrics-core 3.2.4 io.micrometer micrometer-core 1.0.0 org.slf4j slf4j-api 1.7.25 ``` 连接工厂: ```java package com.example.simple; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; /** * RabbitMQ连接工具类 */ public class ConnectionUtils { /** * 获取RabbitMQ连接 */ public static Connection getConnection() throws IOException, TimeoutException { //定义连接工厂 ConnectionFactory connectionFactory = new ConnectionFactory(); //设置服务地址 connectionFactory.setHost("127.0.0.1"); //设置AMQP监听端口 connectionFactory.setPort(5672); //设置vhost connectionFactory.setVirtualHost("/example"); //用户名 connectionFactory.setUsername("admin"); //密码 connectionFactory.setPassword("admin"); return connectionFactory.newConnection(); } } ``` 生产者: ```java package com.example.simple; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 生产者:发布消息 */ public class Producer { //定义队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //创建队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //定义要发送的消息 String msg = "Hello RabbitMQ!"; channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("----发送了一条消息:" + msg); //关闭资源连接 channel.close(); connection.close(); } } ``` 查看发送的消息: ![1555121773572](README.assets/1555121773572.png) ![1555121514373](README.assets/1555121514373.png) 消费者: 获取队列消息(旧方法):通过循环监听(严重浪费性能) ```java package com.example.simple; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 消费者:获取生产者发送的消息 */ public class Consumer { //获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_name"; private static void oldMethod() throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建通道 Channel channel = connection.createChannel(); //定义队列消费者 (3.* 方法使用,最新版已经废弃,要想使用需要降低maven相关版本) QueueingConsumer consumer = new QueueingConsumer(channel); //监听队列 channel.basicConsume(QUEUE_NAME, true, consumer); while (true){ QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String msg = new String(delivery.getBody()); System.out.println("****收到了一条消息:" + msg); } } } ``` 新API方法:利用监听器机制 ```java //获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body); System.out.println("****收到了一条消息:" + msg); } }; //监听队列 channel.basicConsume(QUEUE_NAME, consumer); } ``` 运行后便得到了消息: ![1555121730673](README.assets/1555121730673.png) 控制台查看消息已经没有了: ![1555121792916](README.assets/1555121792916.png) * 缺点 耦合性高 ,生产者一一对应消费者对列名变更,要同时变更代码 #### **3.3 Work queues工作队列** * 模型:同一个队列多个消费者 ![1555122028961](README.assets/1555122028961.png) ##### **3.3.1 轮询分发** 定义多个消费者,如果每个消费者消费的消息都一样多,这叫做轮询分发(round-robin) 生产者:发送50个消息 ```java package com.example.work; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 工作队列之轮询分发生产者 */ public class Producer { //定义队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //创建队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); for(int i = 0; i < 50; i++){ //定义要发送的消息 String msg = "Message [" + i + "]"; //发送消息 channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("----发送了一条消息:" + msg); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } //关闭资源连接 channel.close(); connection.close(); } } ``` 消费者1: ```java package com.example.work; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 工作队列之轮询分发消费者1 */ public class Consumer1 {//获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); } } }; //监听队列 boolean autoAck = true; //自动应答 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 消费者2: ```java package com.example.work; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * 工作队列之轮询分发消费者2 */ public class Consumer2 {//获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); } } }; //监听队列 boolean autoAck = true; //自动应答 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 注意先启动两个消费者,不然先启动生产者发送消息,再启动消费者时候,第一个消费者启动完成了会直接把所有的消息都消费掉,导致观察不到轮询分发的现象。现在我们先启动了两个消费者等待消息,再启动生产者发送消息: ![1555122363508](README.assets/1555122363508.png) 消费者1控制台输出: ![1555122663237](README.assets/1555122663237.png) 消费者2控制台输出: ![1555122682785](README.assets/1555122682785.png) 可以看到两个消费者依次消费消息,且保证两个消费的的数量公平性; ##### **3.3.2 公平分发** 公平分发:采用手动应答的方式,即消费者处理完成通知队列处理完成,这样处理快的客户端可以分到更多的消息 生产者: ```java package com.example.workfair; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 工作队列之公平分发生产者 */ public class Producer { //定义队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //创建队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //设置每次发送到队列的消息只有一个,需要等到消费者发送处理完的响应后才继续发送消息 int prefetchCount = 1; channel.basicQos(prefetchCount); for(int i = 0; i < 50; i++){ //定义要发送的消息 String msg = "Message [" + i + "]"; //发送消息 channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("----发送了一条消息:" + msg); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } //关闭资源连接 channel.close(); connection.close(); } } ``` 重点在于消息的再次发送等待前一个消费完成: ![1555126208038](README.assets/1555126208038.png) 消费者1: ```java package com.example.workfair; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.*; import java.io.IOException; import java.util.concurrent.TimeoutException; /** * 工作队列之公平分发消费者1 */ public class Consumer1 {//获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 消费者2: ```java package com.example.workfair; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 工作队列之公平分发消费者2 */ public class Consumer2 {//获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_name"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 启动消费者再启动生产者后: 消费者1消费: ![1555126386319](README.assets/1555126386319.png) 消费者2消费: ![1555126403923](README.assets/1555126403923.png) 可以看到两个消费者消费消息并不是公平的,谁消费的快谁处理的消息就多; #### **3.4 消息应答ack与消息持久化durable** * boolean autoAck = true 自动确认模式:一旦rabbitmq将消息分发给消费者,就会从内存中删除; 缺点:如果杀死正在执行的消费者,就会丢失正在处理的消息; * boolean autoAck = false 手动确认模式:如果有一个消费者挂掉,就会交付给其他消费者; rabbitmq支持消息应答,消费者发送一个消息应答,告诉rabbitmq这个消息我已经处理完成,你可以删除了,然后rabbitmq就会删除内存中的消息; * 消息应答默认是打开的,但是如果rabbitmq的服务器挂了,消息会消失,所以需要持久化消息 消息持久化: ```java //声明队列 boolean durable = false; channel.queueDeclare(QUEUE_NAME, durable, false, false, null); ``` 对于已经定义的队列queue,不允许重新定义; #### **3.5 publish_subscribe订阅模式** * 模型 ![1555140348050](README.assets/1555140348050.png) 1、一个生产者,多个消费者; 2、每个消费者都有自己的队列; 3、生产者没有直接把消息发送到队列,而是发送到了交换机 转发器 exchange; 4、每个队列都要绑定到交换机上; 5、生产者发送的消息经过交换机 到达队列 就能实现 一个消息被多个消费者消费; * 代码示例 生产者: ```java package com.example.ps; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 订阅模式生产者:只负责把消息发送到交换机 */ public class Producer { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_name"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //声明交换机 channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); //分发 //发送消息 String msg = "Hello Publish_Subscribe !"; channel.basicPublish(EXCHANGE_NAME, "", null, msg.getBytes()); System.out.println("****发送了一条消息:" + msg); //关闭资源连接 channel.close(); connection.close(); } } ``` 控制台查看交换机: ![1555140629138](README.assets/1555140629138.png) ![1555140649068](README.assets/1555140649068.png) **但是却不存在消息,因为消息已经丢失了,交换机是没有存储消息的能力的,只有队列queue能存储消息,所以我们需要消费者产生队列绑定到交换机exchange** 消费者1: ```java package com.example.ps; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 订阅模式消费者1:产生一个队列,绑定到交换机,获取消息 */ public class Consumer1 { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_name"; //设置消息的队列名称,例如发送邮件的队列 private static final String QUEUE_NAME = "test_queue_email"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 消费者2: ```java package com.example.ps; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 订阅模式消费者2:产生一个队列,绑定到交换机,获取消息 */ public class Consumer2 { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_name"; //设置消息的队列名称,例如发送短信的队列 private static final String QUEUE_NAME = "test_queue_sms"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 现在生产者发送一条消息试试: ![1555140774384](README.assets/1555140774384.png) 消费者1和消费者2都接收到了这条消息: ![1555140822107](README.assets/1555140822107.png) * 转发器 Exchange(交换机 转发器):一方面接受生产者的消息,另一方面向队列推送消息匿名转发; 上面例子指定了fanout模式Fanout(不处理路由键); ![1555140880454](README.assets/1555140880454.png) #### **3.6 路由模式** * 模型 Direct (处理路由键):将消息发送到指定的、匹配的队列相当于身份标识,根据标识匹配; 相当于一堆队列绑定到路由,路由发送消息并不是直接发送到所有队列,而是根据设置的匹配标识来将消息发送到指定队列; ![1555141110578](README.assets/1555141110578.png) ![1555141117596](README.assets/1555141117596.png) * 代码示例 生产者: ```java package com.example.routing; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 路由模式生产者 */ public class Producer { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_direct"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //声明交换机,设置为路由模式 channel.exchangeDeclare(EXCHANGE_NAME, "direct"); //发送消息 String msg = "Hello Publish_Subscribe !"; //定义路由键 String routingKey = "info"; channel.basicPublish(EXCHANGE_NAME, routingKey, null, msg.getBytes()); System.out.println("****发送了一条消息:" + msg); //关闭资源连接 channel.close(); connection.close(); } } ``` 消费者1: ```java package com.example.routing; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 路由模式消费者1:产生一个队列,绑定到交换机,从队列中获取指定路由键类型的消息 */ public class Consumer1 { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_direct"; //设置消息的队列名称,例如发送邮件的队列 private static final String QUEUE_NAME = "test_queue_direct_1"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 String routingKey = "error"; channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, routingKey); //指定队列路由键 //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 消费者2: ```java package com.example.routing; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 路由模式消费者2:产生一个队列,绑定到交换机,从队列中获取指定路由键类型的消息 */ public class Consumer2 { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_direct"; //设置消息的队列名称,例如发送邮件的队列 private static final String QUEUE_NAME = "test_queue_direct_2"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "info"); //指定队列路由键 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "warning"); //指定队列路由键 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "error"); //指定队列路由键 //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 测试结果: Producer生产者发送 error类型路由键的消息: ![1555147092501](README.assets/1555147092501.png) 消费者1和消费者2都能接收到消息: ![1555147120227](README.assets/1555147120227.png) 生产者发送一条info类型路由键消息: ![1555147156227](README.assets/1555147156227.png) 只有消费者2能接收到: ![1555147194993](README.assets/1555147194993.png) 因为消费者2设置接收的路由键类型是包含info的: ![1555147234314](README.assets/1555147234314.png) 而消费者1只有error: ![1555147253037](README.assets/1555147253037.png) #### **3.7 主题模式** * 模型 Topic exchange :将路由键和某模式匹配(根据规则匹配查找对应的队列) \# 匹配一个或多个 \* 匹配一个 例如 发送 goods.add.one ,goods.# 能匹配 goods.* 不能匹配,但是发送 goods.add 都能匹配; 相当于正则表达式匹配了; ![1555206609199](README.assets/1555206609199.png) ![1555206615768](README.assets/1555206615768.png) * 代码示例 生产者: ```java package com.example.topic; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 主题模式生产者:例如发布一个商品信息消息 */ public class Producer { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_topic"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //声明交换机,设置为主题模式 channel.exchangeDeclare(EXCHANGE_NAME, "topic"); //发送消息 String msg = "Hello Topic !"; //发布主题消息 String type = "goods.delete"; channel.basicPublish(EXCHANGE_NAME, type, null, msg.getBytes()); System.out.println("****发送了一条消息:" + msg + " ;类型:" + type); //关闭资源连接 channel.close(); connection.close(); } } ``` 消费者1: ```java package com.example.topic; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 主题模式消费者1:产生一个队列,绑定到交换机,根据主题匹配规则接受消息 */ public class Consumer1 { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_topic"; //设置消息的队列名称 private static final String QUEUE_NAME = "test_queue_topic_1"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.#"); //规则定义为接收goods. 所有类型消息 //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 消费者2: ```java package com.example.topic; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 主题模式消费者2:产生一个队列,绑定到交换机,根据主题匹配规则接受消息 */ public class Consumer2 { //定义交换机名称 private static final String EXCHANGE_NAME = "test_exchange_topic"; //设置消息的队列名称 private static final String QUEUE_NAME = "test_queue_topic_2"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 final Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //绑定队列到交换机 channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "goods.add"); //只接收类型为goods.add的消息 //保证队列一次只分发一个 channel.basicQos(1); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body, "UTF-8"); System.out.println("****收到了一条消息:" + msg); try { //模拟业务耗时操作 Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); }finally { System.out.println(msg + ":处理完成"); //处理完成手动应答 channel.basicAck(envelope.getDeliveryTag(), false); } } }; //监听队列 boolean autoAck = false; //自动应答关闭 channel.basicConsume(QUEUE_NAME, autoAck,consumer); } } ``` 生产者生产一条 goods.delete 的消息: ![1555206834343](README.assets/1555206834343.png) 消费者1消费了消息: ![1555206876544](README.assets/1555206876544.png) 因为消费者1设置的模式能够匹配发送的消息格式: ![1555206911742](README.assets/1555206911742.png) 生产者生产一条goods.add的消息: ![1555206956355](README.assets/1555206956355.png) 消费1和消费者2都消费到了消息: ![1555206985716](README.assets/1555206985716.png) 消费者1的goods.#能够匹配上述两条消息,消费2的goods.add只能消费goods.add消息,所以能接收到第二条消息; ### **4. 消息确认机制(事务+confirm)** 在rabbitmq中我们可以通过持久化数据解决rabbitmq服务器异常导致数据丢失问题; 问题:生产者将消息发送出去之后,消息到底有没有成功的到达rabbitmq服务器,默认情况下是不知道的; 解决方案: 两者方式: I. AMQP 实现了事务机制 II. Confirm模式 #### 4.1 事务机制 * 基本操作 **txSelect** : 用户将当前channel设置成transaction模式; **txCommit** : 用于提交事务; **txRollback** : 回滚事务; * 代码示例 生产者: ```java package com.example.tx; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; /** * 事务管理 */ public class Producer { //定义队列名称 private static final String QUEUE_NAME = "test_queue_transaction"; public static void main(String[] args) throws IOException, TimeoutException { //获取一个连接 Connection connection = ConnectionUtils.getConnection(); //从连接中获取一个通道 Channel channel = connection.createChannel(); //创建队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); try{ //开启事务 channel.txSelect(); //定义要发送的消息 String msg = "Hello Transaction!"; channel.basicPublish("", QUEUE_NAME, null, msg.getBytes()); System.out.println("----发送了一条消息:" + msg); //提交事务 channel.txCommit(); }catch (Exception e){ //事务回滚 channel.txRollback(); System.out.println("产生异常,消息未成功发送!"); } //关闭资源连接 channel.close(); connection.close(); } } ``` 消费者: ```java package com.example.tx; import java.io.IOException; import java.util.concurrent.TimeoutException; import com.example.simple.ConnectionUtils; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.Envelope; /** * 简单队列消费者 */ public class Consumer { //获取消息的队列名称 private static final String QUEUE_NAME = "test_queue_transaction"; public static void main(String[] args) throws IOException, TimeoutException, InterruptedException { //获取连接 Connection connection = ConnectionUtils.getConnection(); //创建频道 Channel channel = connection.createChannel(); //队列声明 channel.queueDeclare(QUEUE_NAME, false, false, false, null); //定义消费者 DefaultConsumer consumer = new DefaultConsumer(channel){ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String msg = new String(body); System.out.println("****收到了一条消息:" + msg); } }; //监听队列 channel.basicConsume(QUEUE_NAME, consumer); } } ``` 我们先开启消费者等待消费,然后生产者发送消息,正常情况下生产者发送消息,消费者接收到消息; 但是期间产生了异常,不过我们用事务进行处理,保证消息并未发送出去: ![1555223616128](README.assets/1555223616128.png)