一、背景

​ 最近项目中需要用到了RabbitMQ来监听消息队列,监听的消息队列的 虚拟主机(virtualHost)和队列名(queueName)是不一致的,但是接收到的消息格式相同的。而且可能还存在程序不停机的情况下,动态的增加新的队列(queue)的监听,因此就需要我们自己在程序中实现一种方法实现动态配置RabbitMQ

二、需求

我们有2RabbitMQ的配置,在程序启动的时候,动态的配置好这2个RabbitMQ,实现消息的监听。

RabbitMQ的配置信息

host port username password virtualHost queueName
47.101.130.164 5672 rabbit-multi-01 rabbit-multi-01 /rabbit-multi-01 queue-rabbit-multi-01
47.101.130.164 5672 rabbit-multi-02 rabbit-multi-02 /rabbit-multi-02 queue-rabbit-multi-02

三、实现思路

1、动态配置RabbitMQ

包括 ConnectionFactory,RabbitAdmin,RabbitTemplate,SimpleMessageListenerContainer

2、将上方配置好的Bean注入到Spring容器中,之后可能需要用到

Spring容器中注入Bean的方法

DefaultListableBeanFactory#registerSingleton
DefaultListableBeanFactory#registerBeanDefinition

四、实现步骤

1、引入maven依赖

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2、创建RabbitProperties用来表示RabbitMQ的配置信息

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RabbitProperties {
private String host;
private Integer port;
private String username;
private String password;
private String virtualHost;
private String queueName;
}

3、配置RabbitMQ

配置 ConnectionFactory,RabbitAdmin,RabbitTemplate,SimpleMessageListenerContainer等,并动态注入到Spring容器中

@Configuration
@RequiredArgsConstructor
@Slf4j
public class MultiRabbitMqConfig { private final DefaultListableBeanFactory defaultListableBeanFactory; private static Map<String, RabbitProperties> multiMqPropertiesMap = new HashMap<String, RabbitProperties>() {
{
put("first", RabbitProperties.builder()
.host("47.101.130.164")
.port(5672)
.username("rabbit-multi-01")
.password("rabbit-multi-01")
.virtualHost("/rabbit-multi-01")
.queueName("queue-rabbit-multi-01").build());
put("second", RabbitProperties.builder()
.host("47.101.130.164")
.port(5672)
.username("rabbit-multi-02")
.password("rabbit-multi-02")
.virtualHost("/rabbit-multi-02")
.queueName("queue-rabbit-multi-02").build());
}
}; @PostConstruct
public void initRabbitmq() {
multiMqPropertiesMap.forEach((key, rabbitProperties) -> { AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(CachingConnectionFactory.class)
.addPropertyValue("cacheMode", CachingConnectionFactory.CacheMode.CHANNEL)
.addPropertyValue("host", rabbitProperties.getHost())
.addPropertyValue("port", rabbitProperties.getPort())
.addPropertyValue("username", rabbitProperties.getUsername())
.addPropertyValue("password", rabbitProperties.getPassword())
.addPropertyValue("virtualHost", rabbitProperties.getVirtualHost())
.getBeanDefinition();
String connectionFactoryName = String.format("%s%s", key, "ConnectionFactory");
defaultListableBeanFactory.registerBeanDefinition(connectionFactoryName, beanDefinition);
CachingConnectionFactory connectionFactory = defaultListableBeanFactory.getBean(connectionFactoryName, CachingConnectionFactory.class); String rabbitAdminName = String.format("%s%s", key, "RabbitAdmin");
AbstractBeanDefinition rabbitAdminBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(RabbitAdmin.class)
.addConstructorArgValue(connectionFactory)
.addPropertyValue("autoStartup", true)
.getBeanDefinition();
defaultListableBeanFactory.registerBeanDefinition(rabbitAdminName, rabbitAdminBeanDefinition);
RabbitAdmin rabbitAdmin = defaultListableBeanFactory.getBean(rabbitAdminName, RabbitAdmin.class);
log.info("rabbitAdmin:[{}]", rabbitAdmin); RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
defaultListableBeanFactory.registerSingleton(String.format("%s%s", key, "RabbitTemplate"), rabbitTemplate); SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);
// 设置监听的队列
simpleMessageListenerContainer.setQueueNames(rabbitProperties.getQueueName());
// 指定要创建的并发使用者的数量,默认值是1,当并发高时可以增加这个的数值,同时下方max的数值也要增加
simpleMessageListenerContainer.setConcurrentConsumers(3);
// 最大的并发消费者
simpleMessageListenerContainer.setMaxConcurrentConsumers(10);
// 设置是否重回队列
simpleMessageListenerContainer.setDefaultRequeueRejected(false);
// 设置签收模式
simpleMessageListenerContainer.setAcknowledgeMode(AcknowledgeMode.MANUAL);
// 设置非独占模式
simpleMessageListenerContainer.setExclusive(false);
// 设置consumer未被 ack 的消息个数
simpleMessageListenerContainer.setPrefetchCount(1);
// 设置消息监听器
simpleMessageListenerContainer.setMessageListener((ChannelAwareMessageListener) (message, channel) -> {
try {
log.info("============> Thread:[{}] 接收到消息:[{}] ", Thread.currentThread().getName(), new String(message.getBody()));
log.info("====>connection:[{}]", channel.getConnection());
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
log.error(e.getMessage(), e);
// 发生异常此处需要捕获到
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
}
});
/**
* 1、simpleMessageListenerContainer.start();
* 2、simpleMessageListenerContainer.stop();
* 3、如果后期rabbitmq 的配置是从数据库中读取,即用户在页面上添加一个配置,就动态创建这个
* 此时就需要调用 SimpleMessageListenerContainer#start 方法
*/
defaultListableBeanFactory.registerSingleton(String.format("%s%s", key, "SimpleMessageListenerContainer"), simpleMessageListenerContainer);
});
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
RabbitTemplate firstRabbitTemplate = (RabbitTemplate) defaultListableBeanFactory.getBean("firstRabbitTemplate");
firstRabbitTemplate.convertAndSend("exchange-rabbit-multi-01", "", "first queue message");
log.info("over...");
}).start();
}
}

五、实现效果

六、代码

https://gitee.com/huan1993/rabbitmq/tree/master/rabbitmq-springboot-multi

SpringBoot整合多个RabbitMQ的更多相关文章

  1. Springboot整合二 集成 rabbitmq

    1.在application.yml文件中进行RabbitMQ的相关配置先上代码 spring: rabbitmq: host: 192168.21.11 port: username: guest ...

  2. RabbitMQ与SpringBoot整合

    RabbitMQ  SpringBoot  一.RabbitMQ的介绍 二.Direct模式 三.Topic转发模式 四.Fanout Exchange形式 原文地址: https://www.cnb ...

  3. springboot学习笔记-6 springboot整合RabbitMQ

    一 RabbitMQ的介绍 RabbitMQ是消息中间件的一种,消息中间件即分布式系统中完成消息的发送和接收的基础软件.这些软件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿 ...

  4. Rabbitmq基本使用 SpringBoot整合Rabbit SpringCloud Stream+Rabbit

    https://blog.csdn.net/m0_37867405/article/details/80793601 四.docker中使用rabbitmq 1. 搭建和启动 使用地址:rabbitm ...

  5. 【SpringBoot系列5】SpringBoot整合RabbitMQ

    前言: 因为项目需要用到RabbitMQ,前几天就看了看RabbitMQ的知识,记录下SpringBoot整合RabbitMQ的过程. 给出两个网址: RabbitMQ官方教程:http://www. ...

  6. SpringBoot系列八:SpringBoot整合消息服务(SpringBoot 整合 ActiveMQ、SpringBoot 整合 RabbitMQ、SpringBoot 整合 Kafka)

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合消息服务 2.具体内容 对于异步消息组件在实际的应用之中会有两类: · JMS:代表作就是 ...

  7. SpringBoot28 RabbitMQ知识点、Docker下载RabbitMQ、SpringBoot整合RabbtiMQ

    1 RabbitMQ知识点 1.1 整体架构图 消息生产者将消息投递到exchange中,exchange会以某种路由机制将生产者投递的消息路由到queue中,消息消费者再从queue中获取消息进行消 ...

  8. 一篇学习完rabbitmq基础知识,springboot整合rabbitmq

    一   rabbitmq 介绍 MQ全称为Message Queue,即消息队列, RabbitMQ是由erlang语言开发,基于AMQP(Advanced MessageQueue 高级消息队列协议 ...

  9. 【MQ中间件】RabbitMQ -- SpringBoot整合RabbitMQ(3)

    1.前言说明 前面一篇博客中提到了使用原生java代码进行测试RabbitMQ实现多种交换机类型的队列场景.但是在项目中我们一般使用SpringBoot项目,而且RabbitMQ天生对于Spring的 ...

随机推荐

  1. 1.深入TiDB:初见TiDB

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/584 本篇文章应该是我研究的 TiDB 的第一篇文章,主要是介绍整个 ...

  2. 以人为本打造“超职季”IP,58同城精准匹配企业招聘与打工人

    撰文 |懂懂 编辑 | 秦言 来源:懂懂笔记 在大手笔培育IP的背后,58同城是如何考量的? 在餐厅当服务员的李阿姨今年54岁了.她的女儿马上研究生毕业,非常喜欢陈伟霆,手机屏保都是他.李阿姨没想到, ...

  3. jQuery判断多种数据类型

    1.判断是否为数组类型 var obj=[0]; alert((typeof obj=='object')&&obj.constructor==Array)   2. 判断是否为字符串 ...

  4. 判断输入框中输入的日期格式为yyyy-mm-dd和正确的日期

    判断输入框中输入的日期格式为yyyy-mm-dd和正确的日期   function IsDate(str) { //如果是正确的日期格式返回true,否则返回false var regExp; reg ...

  5. lua中的随机数

    Lua 生成随机数需要用到两个函数:math.randomseed(xx), math.random([n [, m]]) 1. math.randomseed(n) 接收一个整数 n 作为随机序列种 ...

  6. 【转】.net core开发windows服务

    .net core开发windows服务 文建Blog

  7. go相关

    mac 上build go  如果想要在centos上面执行 必须使用下面的方式 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o hello ...

  8. 可选链运算符、空值合并运算符 --应用到vue项目

    1.npm安装 npm install @babel/plugin-proposal-optional-chaining // 可选链运算符 ?. npm install @babel/plugin- ...

  9. Vmware 15 安装 win7 虚拟机 (初学者操作与详解教程)

    @ 目录 一.镜像下载 1.什么是镜像 2.常见的系统镜像文件格式 3.下载win7旗舰版镜像 二.VMware Workstation 下载 1.什么是虚拟机 2.VMware 主要功能 3.VMw ...

  10. java中链表和数组的区别?

    综述:数组是线性结构,可以直接索引,即要去第i个元素,a[i]即可.链表也是线性结构,要取第i个元素,只需用指针往后遍历i次就可.貌似链表比数组还要麻烦些,而且效率低些. 想到这些相同处中的一些细微的 ...