rabbitmq相关

工作队列模型

workQueue,多个消费者绑定到一个队列,当队列堆积消息时,可使用work模型。

多个消费者绑定一个队列,同一条消息只会被一个消费者处理

通过设置prefetch来控制消费者预取的消息数量

spring:
  rabbitmq:
    listener:
      simple:
        prefetch: 1 # 每次只能获取一条消息,处理完成才能获取下一个消息

发布订阅模型

角色类型如下:

publisher,生产者

exchange,交换机,负责转发消息,不负责存储消息的能力

交换机类型如下:

Fanout,广播,将消息交给所有绑定交换机的队列

Direct,定向,把消息交给符合制定routing key的队列

Topic,通配符,把消息交给符合routing pattern的队列

consumer,消费者

queue,消息队列

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

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

生产者代码

复制代码
    public static final String EXCHANGE_NAME = "fanout_exchange";
    public static final String QUEUE_NAME = "fanout_queue1";    

    @Bean("fanout_exchange")//交换机
    public Exchange exchange(){
        return ExchangeBuilder.fanoutExchange(EXCHANGE_NAME).durable(true).build();
    }

    @Bean("fanout_queue1")//消息队列
    public Queue queue(){
        return QueueBuilder.durable(QUEUE_NAME).build();
    }

    @Bean//绑定交换机和消息队列1
    public Binding binding(@Qualifier("fanout_exchange")Exchange exchange,@Qualifier("fanout_queue1")Queue queue){
        return BindingBuilder.bind(queue).to(exchange).with("").noargs();
    }
    @Bean("fanout_queue2")//消息队列2
    public Queue queue2(){
        return QueueBuilder.durable("fanout_queue2").build();
    }

    @Bean//绑定交换机和消息队列2
    public Binding binding2(@Qualifier("fanout_exchange")Exchange exchange,@Qualifier("fanout_queue2")Queue queue){
        return BindingBuilder.bind(queue).to(exchange).with("").noargs();
    }
复制代码

发送消息

    @Test
    void fanout_exchangeTest() {
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_NAME,"","fanout,这是在广播...");
    }

消费者

复制代码
    @RabbitListener(queues = "fanout_queue1")
    public void listenFanoutQueue1(Message message) {
        System.out.println("消费者1收到:"+new String(message.getBody()));
    }

    @RabbitListener(queues = "fanout_queue2")
    public void listenFanoutQueue2(Message message) {
        System.out.println("消费者2收到:"+new String(message.getBody()));
    }
复制代码

 ------------------------------------------------------------------------------------------------------------------------------------ --------------

 在Direct模型下:

- 队列与交换机的绑定,不能是任意绑定了,而是要指定一个`RoutingKey`(路由key)
- 消息的发送方在 向 Exchange发送消息时,也必须指定消息的 `RoutingKey`。
- Exchange不再把消息交给每一个绑定的队列,而是根据消息的`Routing Key`进行判断,只有队列的`Routingkey`与消息的 `Routing key`完全一致,才会接收到消息

基于@Bean的方式声明队列和交换机比较麻烦,Spring还提供了基于注解方式来声明。

在consumer的SpringRabbitListener中添加两个消费者,同时基于注解来声明队列和交换机:

复制代码
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct_queue1"),
     exchange = @Exchange(name = "direct_exchange", type = ExchangeTypes.DIRECT), key = {"red", "blue" }))
    public void listenDirectQueue1(String msg) {
        System.out.println("消费者1收到direct_queue1的消息" + msg);
    }
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct_queue2"),
     exchange = @Exchange(name = "direct_exchange", type = ExchangeTypes.DIRECT), key = {"red", "yellow" }))
    public void listenDirectQueue2(String msg) {
        System.out.println("消费者2收到direct_queue2的消息" + msg);
    }
复制代码

生产者发送消息

      @Test
        void direct_exchangeTest() {
        String exchangeName="direct_exchange";
        String message="由于排放核污水,日本出现哥斯拉";
        // rabbitTemplate.convertAndSend(exchangeName,"red",message);
        rabbitTemplate.convertAndSend(exchangeName,"blue",message);
    }

 ------------------------------------------------------------------------------------------------------------------------------------ --------------

复制代码
`Topic`类型的`Exchange`与`Direct`相比,都是可以根据`RoutingKey`把消息路由到不同的队列。只不过`Topic`类型`Exchange`可以让队列在绑定`Routing key` 的时候使用通配符!
`Routingkey` 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: `item.insert`

 通配符规则:

`#`:匹配一个或多个词

`*`:匹配不多不少恰好1个词

 举例:

 `item.#`:能够匹配`item.spu.insert` 或者 `item.spu`

 `item.*`:只能匹配`item.spu`

复制代码

 添加两个消费者,同时声明队列和交换机

复制代码
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue1"),
    exchange = @Exchange(name = "topic.exchange",type = ExchangeTypes.TOPIC),key = "china.#"))
    public void listenTopicQueue1(String msg){
        System.out.println("消费者1收到topic_queue1的消息" + msg);
    }

    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue2"),
    exchange = @Exchange(name = "topic.exchange",type = ExchangeTypes.TOPIC),key = "#.news"))
    public void listenTopicQueue2(String msg){
        System.out.println("消费者2收到topic_queue2的消息" + msg);
    }
复制代码

生产者

    @Test
    void topic_exchangeTest() {
        String exchangeName="topic.exchange";
        String message="喜报!xxx中了1000万彩票";
        rabbitTemplate.convertAndSend(exchangeName,"china.news",message);
    }

 

消息转换器

Spring会把你发送的消息序列化为字节发送给MQ,接收消息的时候,还会把字节反序列化为Java对象。

默认情况下Spring采用的序列化方式是JDK序列化。

 

.配置JSON转换器

JDK序列化方式并不合适。我们希望消息体的体积更小、可读性更高,因此可以使用JSON方式来做序列化和反序列化。

在publisher和consumer两个服务中都引入依赖:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.10</version>
</dependency>

配置消息转换器。

在启动类中添加一个Bean即可:

@Bean
public MessageConverter jsonMessageConverter(){
    return new Jackson2JsonMessageConverter();
}
posted @   张碧晨  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示