1. 通道绑定对应消息队列和发布消息
参数1:queue表示队列的名称
生产者代码:
代码语言:javascript复制// 通道绑定对应消息队列
// 参数1:队列名称,如果队列不存在会自动创建
// 参数2:用来定义队列特性是否要持久化
// 参数3:是否独占队列,表示只有当前连接可用该队列
// 参数4:是否在消费完成后自动删除队列
// 参数5:额外附加参数
channel.queueDeclare("hello", false, false, false, null);
// 发布消息
// 参数1:交换器名称
// 参数2:队列名称
// 参数3:传递消息额外设置
// 参数4:消息的具体内容
String message = "hello rabbitmq";
channel.basicPublish("", "hello", null, message.getBytes());
注意:如果
hello
队列不存在,则会自动创建。
代码运行后,观察RabbitMQ管理器,消息队列创建成功
如果此时改变通道绑定对应消息队列
代码语言:javascript复制// 通道绑定对应消息队列
// 由hello改为chage
channel.queueDeclare("change", false, false, false, null);
// 发布消息
String message = "hello rabbitmq";
channel.basicPublish("", "hello", null, message.getBytes());
代码运行后,观察RabbitMQ管理器,change
消息队列创建成功,但是消息跑错地方了
如果要往change
消息队列发送消息,则应该修改如下:
String message = "hello rabbitmq";
channel.basicPublish("", "change", null, message.getBytes());
结论:
- 同一个通道可以向不同的队列发送消息
basicPublish
才是决定消息去什么通道,而不是queueDeclare
2. 队列持久化
参数2:durable 表示队列特性是否要持久化,这里设置为 false
,重启RabbitMQ后,所有队列将丢失
// 通道绑定对应消息队列
// 参数1:队列名称,如果队列不存在会自动创建
// 参数2:用来定义队列特性是否要持久化
// 参数3:是否独占队列,表示只有当前连接可用该队列
// 参数4:是否在消费完成后自动删除队列
// 参数5:额外附加参数
channel.queueDeclare("hello", false, false, false, null);
重启MQ服务
代码语言:javascript复制systemctl restart rabbitmq-server
观察RabbitMQ管理器,发现hello
消息队列丢失了
现在将hello
消息队列设置成持久化
channel.queueDeclare("hello", true, false, false, null);
可以看到Features显示为D(durable),表示设置成持久化,此时再重启MQ服务,消息队列不会丢失,但消息丢失了。
结论:
- 如果消息队列不设置持久化,重启MQ服务后,没设置持久化的消息队列将会丢失
- 如果消息队列设置了持久化,但没有设置消息持久化,重启MQ服务后,队列不会丢失,但消息会丢失
消息持久化
从上面我们可以看到,消息队列设置了持久化,但没有设置消息持久化,重启MQ服务后,队列不会丢失,但消息会丢失,怎么解决这个问题呢?
代码语言:javascript复制// 发布消息
// 参数1:交换器名称
// 参数2:队列名称
// 参数3:传递消息额外设置
// 参数4:消息的具体内容
String message = "hello rabbitmq";
//channel.basicPublish("", "hello", null, message.getBytes());
// MessageProperties.PERSISTENT_TEXT_PLAIN 重启后,消息也要持久化
channel.basicPublish("", "hello", MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes());
注意:
- 一开始所有的消息是存储在内存中的
- 当停止的时候,消息才会持久化到硬盘中
- 当启动的时候,将硬盘中的消息读取到内存中
重启MQ服务后,队列和消息恢复成功
生产者与消费者通道绑定的参数一致性
生产者:
代码语言:javascript复制// 通道绑定对应消息队列
// 参数1:队列名称,如果队列不存在会自动创建
// 参数2:用来定义队列特性是否要持久化
// 参数3:是否独占队列,表示只有当前连接可用该队列
// 参数4:是否在消费完成后自动删除队列
// 参数5:额外附加参数
channel.queueDeclare("hello", true, false, false, null);
消费者:
代码语言:javascript复制channel.queueDeclare("hello", false, false, false, null);
通过观察发现,此时的参数2是不一致的,如果此时消费者进行消费,会出现ShutdownSignalException
异常:
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'durable' for queue 'hello' in vhost '/ems': received 'false' but current is 'true', class-id=50, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502)
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:293)
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:141)
... 3 more
消费者只有参数一致才能成功消费
代码语言:javascript复制channel.queueDeclare("hello", true, false, false, null);
输出结果
代码语言:javascript复制输出队列中的内容>>>>>>>>>hello rabbitmq
3. 独占队列
参数3:exclusive 表示是否独占队列,如果设置为true
,表示只有当前连接可以访问该消息队列,其他连接拒绝访问。
当然,在很多场景下,都是设置为false
,允许多个连接访问同一个队列。
// 通道绑定对应消息队列
// 参数1:队列名称,如果队列不存在会自动创建
// 参数2:用来定义队列特性是否要持久化
// 参数3:是否独占队列,表示只有当前连接可用该队列
// 参数4:是否在消费完成后自动删除队列
// 参数5:额外附加参数
channel.queueDeclare("hello", true, false, false, null);
4. 自动删除
参数4:autoDelete 表示是否在消费完成后自动删除队列
代码语言:javascript复制channel.queueDeclare("hello", true, false, true, null);
当我结束消费者程序后,观察RabbitMQ管理器
注意:如果设置为自动删除队列,是消费者程序结束后才执行自动删除,如果程序未结束,则不会执行自动删除