利用Rabbit MQ 实现一对多通知功能(动态添加删除队列交换机)

楼主在项目中需要实现分布式lucene查询,由于lucene的索引是存放在本地的。网上有很多方案实现起来相对比较复杂,故楼主为了简单化针对索引同步问题采用的方案是,如果某一结点发生索引的增删改,通过rabbitmq通知所有lucene节点也进行本地的索引的更改。
fanout类型的exchange虽然可以通知所有队列,但一个队列只能绑定一个消费者(如果绑定多个消费者,只要有一个消费者消费了这个消息,其他的消费者就获得不到这个消息了,至于手动ask经测试不行,具体原因没有细看),然后受spring cloud bus的启发,每个lucene实例都绑定一个独立的队列,所有的队列绑定到同一个exchange,从而实现一对多通知的功能。
同时,考虑到上线和拓展的便捷性,要求队列的添加和绑定全部动态自动完成。代码逻辑不复杂,只是有些类不常用,网上的资料相对较少,故把完整源码贴出来,供大家学习交流。代码质量不高,如有错误欢迎大家及时指正!

package com.unionpay.wash.lucene_service.MQListener;

import com.rabbitmq.http.client.domain.QueueInfo;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitManagementTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.UUID;
@Component
public class MQListener implements CommandLineRunner {
    @Autowired
    private RabbitTemplate template;
    @Autowired
    private AmqpAdmin admin;
    private static String queueName;
    @Override
    public void run(String... args) throws Exception {
        RabbitManagementTemplate managementTemplate = new RabbitManagementTemplate();
        String exchangeName = "lucene_exchange";
        Exchange exchange = managementTemplate.getExchange(exchangeName);
        if (exchange == null) {
            managementTemplate.addExchange(new FanoutExchange(exchangeName));
        }
        List<QueueInfo> queues = managementTemplate.getClient().getQueues();
        for (QueueInfo queueInfo : queues){
            String s = queueInfo.getName();
            String idleSince = queueInfo.getIdleSince();
            if (queueInfo.getConsumerCount() == 0 && s.contains("lucene_index") && idleSince != null){
                managementTemplate.deleteQueue(new Queue(s));
            }
        }
        queueName = "lucene_index_"+UUID.randomUUID();
        managementTemplate.addQueue(new Queue(queueName));
        Binding binding = BindingBuilder.bind(new Queue(queueName)).to(new FanoutExchange(exchangeName));
        admin.declareBinding(binding);
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    try{
                        Object o = template.receiveAndConvert(queueName,100);
                        if (o == null){
                            Thread.sleep(1000);
                        }else{

                            //TODO
                        }
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }catch (AmqpException e){
                        managementTemplate.addQueue(new Queue(queueName));
                        BindingBuilder.bind(new Queue(queueName)).to(new FanoutExchange(exchangeName));
                    }


                }
            }
        });
        thread.start();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
感谢您的提问!在 Spring Boot 中集成 RabbitMQ,可以使用 AMQP 协议来实现消息的发送和接收。在动态创建交换机队列时,可以使用 RabbitAdmin 进行管理。简单来说,您可以在应用程序中创建一个 RabbitAdmin bean,然后使用它来声明交换机队列和绑定,并使用它来发布和消费消息。以下是一个简单的示例: @Configuration public class RabbitConfig { @Autowired private ConnectionFactory connectionFactory; @Bean public RabbitAdmin rabbitAdmin() { return new RabbitAdmin(connectionFactory); } @Bean public SimpleMessageListenerContainer listenerContainer() { SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); container.setQueues(myQueue()); container.setMessageListener(new MyMessageListener()); return container; } @Bean public Queue myQueue() { return new Queue("myQueue"); } @Bean public DirectExchange myExchange() { return new DirectExchange("myExchange"); } @Bean public Binding myBinding() { return BindingBuilder.bind(myQueue()).to(myExchange()).with("myKey"); } @Bean public RabbitTemplate rabbitTemplate() { RabbitTemplate template = new RabbitTemplate(connectionFactory); template.setExchange("myExchange"); template.setRoutingKey("myKey"); return template; } } 在上面的示例中,我们使用 @Configuration 注解来告诉 Spring Boot,我们正在创建一个配置类。我们还使用 @Autowired 注注入 ConnectionFactory 类,因为它是与 RabbitMQ 进行通信的关键。 然后,我们创建了一个 RabbitAdmin bean,该 bean 可以使用我们的 connectionFactory 来管理交换机队列和绑定。我们还创建了一个 SimpleMessageListenerContainer bean,该 bean 可以监听我们的队列并处理来自队列的消息。 我们还创建了一个 Queue bean、一个 DirectExchange bean 和一个 Binding bean,这些 bean 是动态创建交换机队列和绑定的关键。我们将它们添加RabbitAdmin 中,以便在应用程序运行时动态创建它们并将它们绑定在一起。 最后,我们创建了一个 RabbitTemplate bean,该 bean 可以使用我们的 connectionFactory 来发布消息。我们设置了 exchange 和 routingKey 属性,以便在发布消息时指定它们的目标。 这是一个非常基本的示例,仅仅涵盖了 RabbitMQ 动态创建交换机队列的基本概念。实际上,您可能需要更复杂的配置来满足您的需求,但是这个示例可以作为一个起点,让您开始使用 Spring Boot 和 RabbitMQ。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值