一、摘要概述
RabbitMQ(一) – 初识RabbitMQ :通过AMQP协议触摸RabbitMQ整体结构设计
[RabbitMQ(二) – 交换器与队列API探索]juejin.cn/post/684490…) :完成RabbitMQ服务端结构基础学习
RabbitMQ(三) – 消息与队列进阶:本文将会是RabbitMQ基础篇最倒数第二篇,同时也是进阶RabbitMQ第一篇文章。内容将会由基础消息生产衍生到TTL、Priority、MaxLength、DeadLetter等中阶操作
二、基础生产应用
2.1 基础生产API
前面两篇文章已经或多或少接触到生产者与服务端交互,核心在于交换器,生产者不会与数据存储的队列直接耦合。即消息生产发送时必要结构应该有目标交换器、routingKey、消息体
2.2 mandatory详解
String exchangeName = "exchangeName";
String routingKey = "routingKey";
String message = "message";
// 测试mandatory
boolean mandatory = true, immediate = false;
String badRoutingKey = "badRoutingKey";
channel.basicPublish(exchangeName,badRoutingKey,mandatory,immediate,basicProperties,message.getBytes());
// 增加ReturnListener
ReturnListener returnListener = new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange,
String routingKey, AMQP.BasicProperties properties, byte[] body){
System.out.println(new String(body));
}
};
channel.addReturnListener(returnListener);
2.3 备胎交换器
通过添加ReturnListener确实可以保证交换器中未被路由的消息不丢失,但是引发的血案就是客户端逻辑复杂化,反正个人不是很喜欢在正常逻辑中处理意外情况,这样会导致后期迭代、维护成本上升。这时候就可以通过备胎交换器解决
交换器创建时绑定一个备胎交换器,当消息没有对应路由队列时就会转发到这个备胎交换器,这与后面讲得死信交换器队列有一定相似之处。通过前面交换器创建代码一直设置为null的第五个参数Map实现,该参数通过key-value形式设置一些属性特征,后面队列也会使用到这个Map
key为 alternate-exchange,value为备胎交换器名称
// 创建备胎交换器与队列
String alternateExchangeName = "alternateExchange",alternateQueueName = "alternateQueue";
String alternateBinding = "alternateBinding";
channel.exchangeDeclare(alternateExchangeName,BuiltinExchangeType.DIRECT,true,false,null);
channel.queueDeclare(alternateQueueName,true,false,false,null);
channel.queueBind(alternateQueueName,alternateExchangeName,alternateBinding);
// 将备胎交换器设置到参数中
Map<String,Object> exchangeArgumentMap = new HashMap<>();
exchangeArgumentMap.put("alternate-exchange",alternateExchangeName);
channel.exchangeDeclare("exchangeName", BuiltinExchangeType.DIRECT,true,false,exchangeArgumentMap);
- 通过控制面板查看交换器会有AE标识标识该交换器绑定有备胎交换器
- 备胎交换器路由到队列使用的routingKey为消息携带的routingKey
- 若原消息设置有消息过期等属性转发到备胎交换器路由后依然具备该属性
三、Durable持久化
前面接触到创建交换器Exchange、队列Queue时都会有参数Durable持久化的存在,但是思考一下,队列持久化以后消息就会持久化保存?答案是否定的,可以测试一下这个结论重启RabbitMQ服务应用即可
若想要实现消息的持久化则还需要在发送消息时通过上一节讲到的BasicProperties属性对象完成。该对象中存在诸多属性表示消息的特性,不做集中讲解,拆分到具体特性单元中讲解。回到消息持久化操作上,BasicProperties类中存在属性deliveryMod
- 1:表示消息不持久化
- 2:表示消息持久化
如下所示代码Demo,BasicProperties是一个接口,实例化需要借助与AMQP接口的静态内部类即AMQP.BasicProperties实现。当然还有一点就是该内部类设计了建造者模式,大大方便客户端API操作
AMQP.BasicProperties basicProperties = new AMQP.BasicProperties
.Builder()
.deliveryMode(2)
.build();
channel.basicPublish(exchangeName,routingKey,basicProperties,message.getBytes());
如果单纯仅仅为了消息持久化特性,可以使用MessageProperties枚举类,该类中封装了几种常用BasicProperties对象实例,主要是针对持久化、优先级两个属性。最后提一点就是发送一条消息后可以重启服务器进行验证测试,测试过程结果本文不再赘述
// deliveryMod 为 2表示持久化
// priority 为 0 表示最低优先级
// contentType 为 text/palin表示文本消息
AMQP.BasicProperties persistentTextPlain = MessageProperties.PERSISTENT_TEXT_PLAIN;