5 分钟完成RabbitMQ入门

本篇文章将讲述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 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

    org.springframework.boot
    spring-boot-starter-amqp
  • 具体请看源码,记得修改application.yml 配置哦!!!

拓展

无论是广播还是主题模式,在多节点应用中,当消息发送至同一队列多个消费者时,只有其中一个节点消费了消息,如何拓展为广播效果?

在fanout模式下,使用redis的发布订阅模式来通知其它节点

如何防止消息丢失?

1、生产者确认消息发送
2、交换机、路由、队列设置持久化模式,保证消息不会丢失
3、消费者确认消费消息 ,手动ack

如何防止消息积压?

不推荐使用channel.basicReject(deliveryTag, false),第二个参数为是否重新放回队列,如果使用不当会导致消息一直在消费-入列中循环。

可根据业务设置缓存,当缓存达到一定量时再发送消息。

好,这篇springboot整合rabbitmq教程就暂且到此。

一直在追求思路的传递而非代码的COPY

你可能感兴趣的:(程序员)