本篇文章将讲述springboot
整合rabbitmq
过程,适用于初学者快速入门。内容包括对几种常见的队列模型论述以及实践(路由模式、发布订阅(广播)模式、主题模式);由于这几种模式的队列结果相似,区别在于交换机类型的不同,因此交换机的类型决定了它们之间的工作模式。交换机类型分别对应:直连交换机(Direct Exchange)、扇型交换机(Fanout Exchange)、Topic Exchange(主题交换机)。因此以下涉及的知识和代码多围绕交换机
去展开论述。
三种模式
路由模式
生产者将携带路由键的消息发送给直连交换机,交换机根据路由键值转发到队列名为该值的队列
订阅模式(广播)
生产者将消息发送给扇型交换机,交换机将消息分发给所有绑定的队列,但注意同一队列多个消费者只有其中一个消费了消息。
主题模式
与直连交换机类似,但它的 路由建(routing key) 和 绑定值(key) 是有规则的;拥有上面两种交换机功能。
规则:*:必须存在一个单词;#:存在零个或者多个单词。
了解了以上三种模式流程之后,下面将对三种模式进行代码实战,以加深印象。
代码实战
目录结构
│ RabbitmqApplication.java # 项目启动文件
│
├─config
│ RabbitConfig.java # 生产者确认消息发送配置
│ RabbitConstants.java # 交换机、路由键、队列名常量
│
├─controller
│ MessageController.java # 消息测试API
│
├─message
│ DirectMessage.java # 路由模式消息
│ FanoutMessage.java # 广播消息
│ RabbitMessage.java # 消息基类
│ TopicMessage.java # 主题消息
│
├─receiver
│ MessageReceiver.java # 消息接收类
│
└─service
│ RabbitService.java
│
└─impl
RabbitServiceImpl.java # 发送消息业务
核心代码解析
- 消息基类:
RabbitMessage.java
/**
* 消息内容
*/
private T data;
public RabbitMessage<T> setData(T data) {
this.data = data;
return this;
}
/**
* 消息唯一编号
*/
private String messageId = UUID.randomUUID().toString();
/**
* 消息创建时间
*/
private String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
/**
* 交换机
* @return
*/
public abstract String exchange();
/**
* 路由键
* @return
*/
public abstract String routingKey();
- 发送消息:
RabbitServiceImpl.java
@Override
public void send(RabbitMessage message) {
log.info("【生产者】发送消息:ID:{},交换机:{},路由键:{},内容:{}", message.getMessageId(), message.exchange(), message.routingKey(), message.getData());
if (null == message.exchange()) {
rabbitTemplate.convertAndSend(message.routingKey(), message, new CorrelationData(message.getMessageId()));
} else {
rabbitTemplate.convertAndSend(message.exchange(), message.routingKey(), message, new CorrelationData(message.getMessageId()));
}
}
- 接收消息:
MessageReceiver.java
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = QUEUE_DIRECT, durable = "true"),
exchange = @Exchange(name = EXCHANGE_DIRECT, type = ExchangeTypes.DIRECT)
)
)
@RabbitHandler
public void direct(DirectMessage message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
log.info("【消费者】收到消息:ID:{},交换机:{},路由键:{},内容:{}", message.getMessageId(), message.exchange(), message.routingKey(), message.getData());
channel.basicAck(tag, false);
}
- 依赖:
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- 具体请看源码,记得修改
application.yml
配置哦!!!
拓展
无论是广播还是主题模式,在多节点应用中,当消息发送至同一队列多个消费者时,只有其中一个节点消费了消息,如何拓展为广播效果?
在fanout模式下,使用redis的发布订阅模式来通知其它节点
如何防止消息丢失?
1、生产者确认消息发送
2、交换机、路由、队列设置持久化模式,保证消息不会丢失
3、消费者确认消费消息 ,手动ack
如何防止消息积压?
不推荐使用channel.basicReject(deliveryTag, false)
,第二个参数为是否重新放回队列,如果使用不当会导致消息一直在消费-入列中循环。
可根据业务设置缓存,当缓存达到一定量时再发送消息。
好,这篇springboot
整合rabbitmq
教程就暂且到此。
一直在追求思路的传递而非代码的COPY
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。