posts - 206,  comments - 26,  views - 17万
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

  一、发布/订阅模式

 

简单队列和工作队列的共同特点:所发出的消息只可能被一个消费者消费,因为一旦消费完就会从队列里删除。这样的特点不能满足,需求:当用户支付完成,去通知订单服务、仓储服务、短信服务,让三个服务各自去完成自己的业务。也就是发送订单支付成功的消息要被三个服务收到。
发布订阅模式与之前案例的区别就是允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机)
发布订阅的模型如图:

 

 

可以看到,在订阅模型中,多了一个exchange角色,而且过程略有变化:

- Publisher:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机)
- Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有以下3种类型:
- Fanout:广播,将消息交给所有绑定到交换机的队列
- Direct:定向,把消息交给符合指定routing key 的队列
- Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列
- Consumer:消费者,与以前一样,订阅队列,没有变化
- Queue:消息队列也与以前一样,接收消息、缓存消息。

注意:exchange负责消息路由,而不是存储,路由失败则消息丢失

Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!

  二、发布订阅 -Fanout Exchange

 

 

发布订阅 -Fanout Exchange
Fanout,英文翻译是扇出,我觉得在MQ中叫广播更合适。Fanout Exchange 会将接收到的消息路由到每一个跟其绑定的queue

 

 

 

在广播模式下,消息发送流程是这样的:

- 1) 可以有多个队列
- 2) 每个队列都要绑定到Exchange(交换机)
- 3) 生产者发送的消息,只能发送到交换机,交换机来决定要发给哪个队列,生产者无法决定
- 4) 交换机把消息发送给绑定过的所有队列
- 5) 订阅队列的消费者都能拿到消息

我们的计划是这样的:

- 创建一个交换机 it.fanout,类型是Fanout
- 创建两个队列fanout.queue1和fanout.queue2,绑定到交换机it.fanout

 

  三、发布订阅 -Fanout Exchange演示案例


实现思路:

1.在consumer服务中,利用代码声明队列,交换机,并将两者绑定

2.在consumer服务中,编写两个消费者方法,分别监听fanout.queue1和fanout.queue2
3.在publisher中编写测试方法,向it.fanout发送消息

具体实现步骤:

步骤一:在consumer服务声明Exchange、Queue、Binding

SpringAMQP提供了声明交换机、队列,绑定关系的API,如图:

 

 

在consumer服务中创建一个类, 添加@configuration注解,并声明FanoutExchange、Queue 和绑定对象binding,代码如下:

 

复制代码
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class FanoutConfig {
    /**
     * 声明交换机
     * @return Fanout类型交换机
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("it.fanout");
    }
 
    /**
     * 第1个队列
     */
    @Bean
    public Queue fanoutQueue1(){
        return new Queue("fanout.queue1");
    }
 
    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }
 
    /**
     * 第2个队列
     */
    @Bean
    public Queue fanoutQueue2(){
        return new Queue("fanout.queue2");
    }
 
    /**
     * 绑定队列和交换机
     */
    @Bean
    public Binding bindingQueue2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }
}
复制代码

 

 

步骤二:消息发送

在publisher服务的SpringAmqpTest类中添加测试方法,代码如下:

@Test
public void testFanoutExchange() {
    // 交换机名称
    String exchangeName = "it.fanout";
    // 消息
    String message = "hello, everyone!";
    rabbitTemplate.convertAndSend(exchangeName, "", message);
}

 


步骤三:消息接收

在consumer服务的SpringRabbitListener中添加两个方法,作为消费者:

复制代码
@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg) {
    System.out.println("消费者1接收到Fanout消息:【" + msg + "】");
}
 
@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg) {
    System.out.println("消费者2接收到Fanout消息:【" + msg + "】");
}
复制代码

 


步骤四:测试。运行测试,消费者1、消费者2收到了相同的消息,实现了一次发送,多个消费者都能接收。

总结:交换机的作用:

- 接收publisher发送的消息
- 将消息按照规则路由到与之绑定的队列
- 不能缓存消息,路由失败,消息丢失
- FanoutExchange的会将消息路由到每个绑定的队列

posted on   努力--坚持  阅读(27)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)
点击右上角即可分享
微信分享提示