RabbitMq快速入门
前言
跟随b站黑马视频进行的自学,有不对的地方小伙伴们多多交流讨论:
下面是b站黑马视频的传送门:
b站黑马rabbitmq视频
提示:以下是本篇文章正文内容,下面案例可供参考
一、MQ是什么?
1.1MQ概述
MQ全称Message Queue(消息队列),是在消息的传输过程中保存消息的容器
。多用于分布式系统之间进行通信。
小结
- MQ,消息队列,存储消息的中间件
- 分布式系统通信两种方式:直接远程调用和借助第三方完成间接通信
- 发送方称为生产者,接收方称为消费者
1.2MQ的优势和劣势
优势:
- 应用解耦
- 异步提速
- 削峰填谷
劣势:
- 系统可用性降低:系统引入的外部依赖越多,系统稳定性越差。一旦MQ宕机,就会对业务造成影响
- 系统复杂性提高
- 一致性问题
1.3常见的MQ产品
RabbitMQ | ActiveMQ | RocketMQ | Kafka | |
---|---|---|---|---|
公司/社区 | Rabbit | Apache | 阿里 | Apache |
开发语言 | Erlang | java | java | Scala&Java |
协议支持 | AMQP,XMPP,SMTP,STOMP | OpenWire,STOMP ,REST,xmpp,AMQP | 自定义 | 自定义协议,社区封装了http协议支持 |
客户端支持语言 | 官方支持Erlang,java,Ruby等几乎支持所有语言 | java,c,c++,Python,PHP,Perl,.net | java,c++(不成熟) | 官方支持java,社区 |
单机吞吐量 | 万级(其次) | 万级(最差) | 十万级(最好) | 十万级(次之) |
消息延迟 | 微秒级 | 毫秒级 | 毫秒级 | 毫秒以内 |
功能特性 | 并发能力强,性能极其好,延时低,社区活跃,管理界面丰富 | 老牌产品,成熟度高,文档较多 | MQ功能比较完善,扩展性佳 | 只支持主要的mq功能,毕竟是为大数据领域准备的 |
1.4RabbitMQ简介
AMQP,即Advanced Message Queuing Protocol(高级消息队列协议),是一个网络协议,是应用层协议的一个开发标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递信息,并不受客户端/中间件不同产品,不同的开发语言等限制。2006年,AMQP规范发布。类比HTTP。
1.5RabbitMQ中的相关概念:
Broker
:接收和分发消息的应用,RabbitMQ Server就是Message BrokerVirtual host
:出于多租户和安全因素设计的,把AMQP的基本组件划分到一个虚拟的分组中,类似于网络中的namespace概念。当多个不同的用户使用同一个RabbitMQ Server通过的服务时,可以划分出多个vhost,每个用户在自己的vhost创建exchange/queue等。Connection
:publisher/consumer和Broker之间的TCP连接Channel
:如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开销将是巨大的,效率也较低。Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行通讯,AMQP method包含了channel id帮助客户端和message broker 识别channel,所以channel之间是完全隔离的。channel作为轻量级的Connection极大减少了操作系统建立TCP connection的开销。
RabbitMQ提供了6种工作模式
:简单模式、work queues、Publish/Subscribe发布与订阅模式、Routing路由模式、Topics主题模式、RPC 远程调用模式
1.6JMS
- JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件的API
- JMS是JavaEE规范中的一种,类比JDBC
- 很多消息中间件都实现了JMS规范,例如:ActiveMQ、RabbitMQ官方没有提供JMS的实现包,但是开源社区有
二、RabbitMQ快速入门
需求:使用简单模式完成消息传递
步骤:
- 创建工程(生产者,消费者)
- 分别添加依赖
- 编写生产者发送消息
2.1创建生产者模块
添加rabbitmq 的Java客户端依赖
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
创建producer类,发送消息
public class Producer_HelloWorld {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.209.128");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列queue
/**
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* queue: 队列名
* durable:是否持久化 当mq重启时还在
* exclusive:是否独占。只能有一个消费者监听这个队列
* 当Connection关闭时,是否删除队列
* autoDelete:是否自动删除。当没有connection时,自动删除
* arguments:参数
* */
//如果没有一个名字叫hello_world的队列,则会创建该队列,如果有不会创建
channel.queueDeclare("hello_world",true,false,false,null);
//6.发送消息
/*
* basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
* exchange:交换机名称,简单模式下交换机会使用默认的""
* routingKey:路由名称
* props: 配置信息
* body:发送消息数据
* */
String body = "Hello RabbitMq!";
channel.basicPublish("","hello_world",null,body.getBytes());
//7.释放资源
//channel.close();
//connection.close();
}
}
发送消息成功:
2.2创建消费者模块
添加rabbitmq 的java客户端依赖
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
创建consumer类,接受消息队列
public class Consumer_HelloWorld {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.209.128");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列queue
/**
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* queue: 队列名
* durable:是否持久化 当mq重启时还在
* exclusive:是否独占。只能有一个消费者监听这个队列
* 当Connection关闭时,是否删除队列
* autoDelete:是否自动删除。当没有connection时,自动删除
* arguments:参数
* */
//如果没有一个名字叫hello_world的队列,则会创建该队列,如果有不会创建
channel.queueDeclare("hello_world",true,false,false,null);
//6.接收消息
/*
*basicConsume(String queue, boolean autoAck, Consumer callback)
* queue:队列名称
* autoAck:是否自动确认
* callback: 回调对象
* */
Consumer consumer = new DefaultConsumer(channel){
/*
* 回调方法,当收到消息后,会自动执行该方法
* consumerTag: 标识
* envelope: 获取一些信息,交换机,路由key。。。
* properties: 配置信息
* body: 数据
* */
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag:"+consumerTag);
System.out.println("Exchange:"+envelope.getExchange());
System.out.println("RoutingKey:"+envelope.getRoutingKey());
System.out.println("properties:"+properties);
System.out.println("body:"+new String(body));
}
};
channel.basicConsume("hello_world",true,consumer);
//关闭资源 ? 不要
}
}
消息消息队列:
Ready里面的三个队列被消费,变为0
2.3RabbitMQ工作模型
2.3.1简单模型:
上述入门案例中使用的是简单模式:
- P:生产者,也就是要发送消息的程序
- C:消费者,消息的接收者,会一直等待消息的到来
- queue:消息队列,图中红色部分。类似于一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从中取出消息
2.3.2Work queues工作队列模式
- Work Queues:与入门程序的简单模式相比,多了一个或多个消费端,多个消费端共同消费同一个队列中的消息
- 对于任务过重或者任务较多情况使用工作队列可以调任务处理的速度
创建一个producer类,多发布几次
public class Producer_WorkQueues {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.209.128");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列queue
/**
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* queue: 队列名
* durable:是否持久化 当mq重启时还在
* exclusive:是否独占。只能有一个消费者监听这个队列
* 当Connection关闭时,是否删除队列
* autoDelete:是否自动删除。当没有connection时,自动删除
* arguments:参数
* */
//如果没有一个名字叫hello_world的队列,则会创建该队列,如果有不会创建
channel.queueDeclare("work_queues", true, false, false, null);
//6.发送消息
/*
* basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
* exchange:交换机名称,简单模式下交换机会使用默认的""
* routingKey:路由名称
* props: 配置信息
* body:发送消息数据
* */
for (int i = 1;i<=10;i++){
String body = i+"Hello RabbitMq!";
channel.basicPublish("", "work_queues", null, body.getBytes());
}
//7.释放资源
//channel.close();
//connection.close();
}
}
创建两个consumer类接受发布的消息队列
consumer1跟consumer2的代码一样,在这里只贴一个类的代码:
public class Consumer_WorkQueues1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.209.128");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列queue
/**
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* queue: 队列名
* durable:是否持久化 当mq重启时还在
* exclusive:是否独占。只能有一个消费者监听这个队列
* 当Connection关闭时,是否删除队列
* autoDelete:是否自动删除。当没有connection时,自动删除
* arguments:参数
* */
//如果没有一个名字叫hello_world的队列,则会创建该队列,如果有不会创建
channel.queueDeclare("work_queues",true,false,false,null);
//6.接收消息
/*
*basicConsume(String queue, boolean autoAck, Consumer callback)
* queue:队列名称
* autoAck:是否自动确认
* callback: 回调对象
* */
Consumer consumer = new DefaultConsumer(channel){
/*
* 回调方法,当收到消息后,会自动执行该方法
* consumerTag: 标识
* envelope: 获取一些信息,交换机,路由key。。。
* properties: 配置信息
* body: 数据
* */
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// System.out.println("consumerTag:"+consumerTag);
// System.out.println("Exchange:"+envelope.getExchange());
// System.out.println("RoutingKey:"+envelope.getRoutingKey());
// System.out.println("properties:"+properties);
System.out.println("body:"+new String(body));
}
};
channel.basicConsume("work_queues",true,consumer);
//关闭资源 ? 不要
}
}
运行这三个类,得到结果:
小结:
- 在一个队列中如果有多个消费者,那么消费者之间对于同一个消息的关系是竞争的关系。
- Work Queues对于任务较多情况使用工作队列可以提高任务处理的速度。例如:短信服务部署多个,只需要有一个节点成功发送即可
2.3.3Pub/Sub 订阅模式
在订阅模型中,多了一个Exchange角色,而且过程略有变化:
P:生产者,也就是要发送消息的程序,但是不在发送到队列中,而是发给X(交换机)
C:消费者,消息的接收者,会一直等待消息到来
Queue:消息队列,接收消息,缓存消息
Exchange:交换机(X)。一方面,接受生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有常见的以下3种类型:
Fanout
:广播,将消息交给所有绑定到交换机的队列Direct
:定向,把消息交给符合指定routing key的队列Topic
:通配符,把消息交给符合routing pattern(路由模式)的队列
Exchange
(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息就会丢失!
创建PubSub的producer
依赖都是一样的,创建的连接工厂也一样,下面是producer的代码:
public class Producer_PubSub {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.93.137");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
* exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
* exchange:交换机
* type:交换机类型
* DIRECT("direct"):定向
* FANOUT("fanout"):扇形(广播)
* TOPIC("topic"):通配符的方式
* HEADERS("headers"):参数匹配
*
* durable:是否持久化
* autoDelete:自动删除
* internal:内部使用。一般false
* arguments:参数
*
* */
String exchangeName = "test_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
//6.创建队列
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
/*
* queueBind(String queue, String exchange, String routingKey)
* queue:队列名称
* exchange:交换机名称
* rountingkey: 路由键,绑定规则
* 如果交换机的类型是fanout,rountingkey设置为""
* */
channel.queueBind(queue1Name,exchangeName,"");
channel.queueBind(queue2Name,exchangeName,"");
String body = "日志信息:张三调用了findAll方法...日志级别:info...";
//8.发布消息
channel.basicPublish(exchangeName,"",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
rabbitmq管理页面显示这两条队列消息
每条队列里面都有了消息:
创建PubSub的Consumer
创建两个Consumer,下面是consumer1的代码:
public class Consumer_PubSub1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.93.137");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建队列queue
/**
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* queue: 队列名
* durable:是否持久化 当mq重启时还在
* exclusive:是否独占。只能有一个消费者监听这个队列
* 当Connection关闭时,是否删除队列
* autoDelete:是否自动删除。当没有connection时,自动删除
* arguments:参数
* */
//如果没有一个名字叫hello_world的队列,则会创建该队列,如果有不会创建
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
//6.接收消息
/*
*basicConsume(String queue, boolean autoAck, Consumer callback)
* queue:队列名称
* autoAck:是否自动确认
* callback: 回调对象
* */
Consumer consumer = new DefaultConsumer(channel){
/*
* 回调方法,当收到消息后,会自动执行该方法
* consumerTag: 标识
* envelope: 获取一些信息,交换机,路由key。。。
* properties: 配置信息
* body: 数据
* */
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// System.out.println("consumerTag:"+consumerTag);
// System.out.println("Exchange:"+envelope.getExchange());
// System.out.println("RoutingKey:"+envelope.getRoutingKey());
// System.out.println("properties:"+properties);
System.out.println("body:"+new String(body));
System.out.println("将日志信息打印到控制台.....");
}
};
channel.basicConsume(queue1Name,true,consumer);
//关闭资源 ? 不要
}
}
两个consumer基本一样,只改一下发布的队列名称和生命的队列名称,回调函数里面再打印一下不一样的内容即可。
最后运行consumer,拿到发布的队列消息,打印输出
2.3.4Rounting路由模式
模式说明
- 队列与交换机的绑定,不能是任意绑定,而是要指定一个RountingKey(路由key)
- 消息的发送方在Exchange发送消息时,也必须指定消息的Rountingkey
- Exchange不再把消息交给每一个绑定的队列,而是根据消息的RountingKey进行判断,只有队列的RountingKey与消息的RountingKey完全一致,才会收到消息
创建Producer
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.93.137");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
* exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
* exchange:交换机
* type:交换机类型
* DIRECT("direct"):定向
* FANOUT("fanout"):扇形(广播)
* TOPIC("topic"):通配符的方式
* HEADERS("headers"):参数匹配
*
* durable:是否持久化
* autoDelete:自动删除
* internal:内部使用。一般false
* arguments:参数
*
* */
String exchangeName = "test_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
//6.创建队列
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
/*
* queueBind(String queue, String exchange, String routingKey)
* queue:队列名称
* exchange:交换机名称
* rountingkey: 路由键,绑定规则
* 如果交换机的类型是fanout,rountingkey设置为""
* */
//队列1的绑定 error
channel.queueBind(queue1Name,exchangeName,"error");
//队列2的绑定 info error warning
channel.queueBind(queue2Name,exchangeName,"info");
channel.queueBind(queue2Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"warning");
String body = "日志信息:张三调用了findAll方法...日志级别:info...";
//8.发布消息
channel.basicPublish(exchangeName,"info",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
当我发送了路由名为info的消息队列,该交换机肯定绑定两个队列,队列1绑定一个routingkey,队列2绑定三个routingkey,应该队列2能收到:
创建Consumer
跟pubsub的代码一样,把队列名字改一下,回调函数打印语句改一下就可以,因为发送的是info消息,只有打印控制台的语句能收到,另外一个队列收不到
如果把producer里面发布消息的地方的routingkey改为error,那么都会收到,在此就不演示了
2.3.5Topics通配符模式
模式说明
创建两个队列,队列1接收"*.error"接收以error为结尾的消息,并存入到数据库中。队列2接收以order开头的系统消息和所有的消息,并打印到控制台。
创建producer
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2.设置参数
connectionFactory.setHost("192.168.93.137");//ip:默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setVirtualHost("/xyh");//虚拟机 默认值:/
connectionFactory.setUsername("xyh");//用户名
connectionFactory.setPassword("xyh980616");//密码
//3.获取连接 connection
Connection connection = connectionFactory.newConnection();
//4.创建channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
* exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
* exchange:交换机
* type:交换机类型
* DIRECT("direct"):定向
* FANOUT("fanout"):扇形(广播)
* TOPIC("topic"):通配符的方式
* HEADERS("headers"):参数匹配
*
* durable:是否持久化
* autoDelete:自动删除
* internal:内部使用。一般false
* arguments:参数
*
* */
String exchangeName = "test_topic";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
//6.创建队列
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
/*
* queueBind(String queue, String exchange, String routingKey)
* queue:队列名称
* exchange:交换机名称
* rountingkey: 路由键,绑定规则
* 如果交换机的类型是fanout,rountingkey设置为""
* */
//routingkey 系统的名称.日志的级别
//需求: 所有error级别的日志存入数据库,所有order系统的日志存入数据库
channel.queueBind(queue1Name,exchangeName,"*.error");
channel.queueBind(queue1Name,exchangeName,"order.*");
channel.queueBind(queue2Name,exchangeName,"*.*");
String body = "日志信息:张三调用了findAll方法...日志级别:info...";
//8.发布消息
channel.basicPublish(exchangeName,"goods.info",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
预测只有队列2能获得消息,队列1获取不到
可以看到确实是队列2接收到了,队列1没有接收到