springboot入门系列(五):SpringBoot连接多RabbitMQ源
SpringBoot连接多RabbitMQ源
在实际开发中,很多场景需要异步处理,这时就需要用到RabbitMQ,而且随着场景的增多程序可能需要连接多个RabbitMQ。SpringBoot本身提供了默认的配置可以快速配置连接RabbitMQ,但是只能连接一个RabbitMQ,当需要连接多个RabbitMQ时,默认的配置就不太适用了,需要单独编写每个连接。
在SpringBoot框架中,我们常用的两个类一般是:
RabbitTemplate:作为生产、消费消息使用;RabbitAdmin:作为申明、删除交换机和队列,绑定和解绑队列和交换机的绑定关系使用。
所以我们连接多个RabbitMQ就需要重新建立连接、重新实现这两个类。
代码如下:
配置
application.properties配置文件需要配置两个连接:
server.port=8080
# rabbitmq
v2.spring.rabbitmq.host=host
v2.spring.rabbitmq.port=5672
v2.spring.rabbitmq.username=username
v2.spring.rabbitmq.password=password
v2.spring.rabbitmq.virtual-host=virtual-host
#consume 手动 ack
v2.spring.rabbitmq.listener.simple.acknowledge-mode=manual
#1.当mandatory标志位设置为true时,
# 如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,
# 那么broker会调用basic.return方法将消息返还给生产者;
#2.当mandatory设置为false时,出现上述情况broker会直接将消息丢弃;通俗的讲,
# mandatory标志告诉broker代理服务器至少将消息route到一个队列中,
# 否则就将消息return给发送者;
v2.spring.rabbitmq.template.mandatory=true
#publisher confirms 发送确认
v2.spring.rabbitmq.publisher-confirms=true
#returns callback :
# 1.未送达exchange
# 2.送达exchange却未送道queue的消息 回调returnCallback.(注意)出现2情况时,publisher-confirms 回调的是true
v2.spring.rabbitmq.publisher-returns=true
v2.spring.rabbitmq.listener.simple.prefetch=5
# rabbitmq
v1.spring.rabbitmq.host=host
v1.spring.rabbitmq.port=5672
v1.spring.rabbitmq.username=username
v1.spring.rabbitmq.password=password
v1.spring.rabbitmq.virtual-host=virtual-host
#consume 手动 ack
v1.spring.rabbitmq.listener.simple.acknowledge-mode=manual
#1.当mandatory标志位设置为true时,
# 如果exchange根据自身类型和消息routingKey无法找到一个合适的queue存储消息,
# 那么broker会调用basic.return方法将消息返还给生产者;
#2.当mandatory设置为false时,出现上述情况broker会直接将消息丢弃;通俗的讲,
# mandatory标志告诉broker代理服务器至少将消息route到一个队列中,
# 否则就将消息return给发送者;
v1.spring.rabbitmq.template.mandatory=true
#publisher confirms 发送确认
v1.spring.rabbitmq.publisher-confirms=true
#returns callback :
# 1.未送达exchange
# 2.送达exchange却未送道queue的消息 回调returnCallback.(注意)出现2情况时,publisher-confirms 回调的是true
v1.spring.rabbitmq.publisher-returns=true
v1.spring.rabbitmq.listener.simple.prefetch=5
重写连接工厂
需要注意的是,在多源的情况下,需要在某个连接加上@Primary注解,表示主连接,默认使用这个连接
package com.example.config.rabbitmq;
import com.alibaba.fastjson.JSON;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* Created by shuai on 2019/4/23.
*/
@Configuration
public class MultipleRabbitMQConfig {
@Bean(name = "v2ConnectionFactory")
public CachingConnectionFactory hospSyncConnectionFactory(
@Value("${v2.spring.rabbitmq.host}") String host,
@Value("${v2.spring.rabbitmq.port}") int port,
@Value("${v2.spring.rabbitmq.username}") String username,
@Value("${v2.spring.rabbitmq.password}") String password,
@Value("${v2.spring.rabbitmq.virtual-host}") String virtualHost,
@Value("${v2.spring.rabbitmq.publisher-confirms}") Boolean publisherConfirms,
@Value("${v2.spring.rabbitmq.publisher-returns}") Boolean publisherReturns) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost(virtualHost);
connectionFactory.setPublisherConfirms(publisherConfirms);
connectionFactory.setPublisherReturns(publisherReturns);
return connectionFactory;
}
@Bean(name = "v2RabbitTemplate")
public RabbitTemplate firstRabbitTemplate(
@Qualifier("v2ConnectionFactory") ConnectionFactory connectionFactory,
@Value("${v2.spring.rabbitmq.template.mandatory}") Boolean mandatory) {
RabbitTemplate v2RabbitTemplate = new RabbitTemplate(connectionFactory);
v2RabbitTemplate.setMandatory(mandatory);
v2RabbitTemplate.setConfirmCallback((correlationData, ack, s) -> {
if (!ack) {
// LOGGER.info("{} 发送RabbitMQ消息 ack确认 失败: [{}]", this.name, JSON.toJSONString(object));
} else {
// LOGGER.info("{} 发送RabbitMQ消息 ack确认 成功: [{}]", this.name, JSON.toJSONString(object));
}
});
v2RabbitTemplate.setReturnCallback((message, code, s, exchange, routingKey) -> {
// LOGGER.error("{} 发送RabbitMQ消息returnedMessage,出现异常,Exchange不存在或发送至Exchange却没有发送到Queue中,message:[{}], code[{}], s[{}], exchange[{}], routingKey[{}]", new Object[]{this.name, JSON.toJSONString(message), JSON.toJSONString(code), JSON.toJSONString(s), JSON.toJSONString(exchange), JSON.toJSONString(routingKey)});
});
return v2RabbitTemplate;
}
@Bean(name = "v2ContainerFactory")
public SimpleRabbitListenerContainerFactory hospSyncFactory(
@Qualifier("v2ConnectionFactory") ConnectionFactory connectionFactory,
@Value("${v2.spring.rabbitmq.listener.simple.acknowledge-mode}") String acknowledge,
@Value("${v2.spring.rabbitmq.listener.simple.prefetch}") Integer prefetch
) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setAcknowledgeMode(AcknowledgeMode.valueOf(acknowledge.toUpperCase()));
factory.setPrefetchCount(prefetch);
return factory;
}
@Bean(name = "v2RabbitAdmin")
public RabbitAdmin iqianzhanRabbitAdmin(
@Qualifier("v2ConnectionFactory") ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
// mq主连接
@Bean(name = "v1ConnectionFactory")
@Primary
public CachingConnectionFactory publicConnectionFactory(
@Value("${v1.spring.rabbitmq.host}") String host,
@Value("${v1.spring.rabbitmq.port}") int port,
@Value("${v1.spring.rabbitmq.username}") String username,
@Value("${v1.spring.rabbitmq.password}") String password,
@Value("${v1.spring.rabbitmq.virtual-host}") String virtualHost,
@Value("${v1.spring.rabbitmq.publisher-confirms}") Boolean publisherConfirms,
@Value("${v1.spring.rabbitmq.publisher-returns}") Boolean publisherReturns) {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost(virtualHost);
connectionFactory.setPublisherConfirms(publisherConfirms);
connectionFactory.setPublisherReturns(publisherReturns);
return connectionFactory;
}
@Bean(name = "v1RabbitTemplate")
@Primary
public RabbitTemplate publicRabbitTemplate(
@Qualifier("v1ConnectionFactory") ConnectionFactory connectionFactory,
@Value("${v1.spring.rabbitmq.template.mandatory}") Boolean mandatory) {
RabbitTemplate v1RabbitTemplate = new RabbitTemplate(connectionFactory);
v1RabbitTemplate.setMandatory(mandatory);
v1RabbitTemplate.setConfirmCallback((correlationData, ack, s) -> {
if (!ack) {
// LOGGER.info("{} 发送RabbitMQ消息 ack确认 失败: [{}]", this.name, JSON.toJSONString(object));
} else {
// LOGGER.info("{} 发送RabbitMQ消息 ack确认 成功: [{}]", this.name, JSON.toJSONString(object));
}
});
v1RabbitTemplate.setReturnCallback((message, code, s, exchange, routingKey) -> {
// LOGGER.error("{} 发送RabbitMQ消息returnedMessage,出现异常,Exchange不存在或发送至Exchange却没有发送到Queue中,message:[{}], code[{}], s[{}], exchange[{}], routingKey[{}]", new Object[]{this.name, JSON.toJSONString(message), JSON.toJSONString(code), JSON.toJSONString(s), JSON.toJSONString(exchange), JSON.toJSONString(routingKey)});
});
return v1RabbitTemplate;
}
@Bean(name = "v1ContainerFactory")
@Primary
public SimpleRabbitListenerContainerFactory insMessageListenerContainer(
@Qualifier("v1ConnectionFactory") ConnectionFactory connectionFactory,
@Value("${v1.spring.rabbitmq.listener.simple.acknowledge-mode}") String acknowledge,
@Value("${v1.spring.rabbitmq.listener.simple.prefetch}") Integer prefetch) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setAcknowledgeMode(AcknowledgeMode.valueOf(acknowledge.toUpperCase()));
factory.setPrefetchCount(prefetch);
return factory;
}
@Bean(name = "v1RabbitAdmin")
@Primary
public RabbitAdmin publicRabbitAdmin(
@Qualifier("v1ConnectionFactory") ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
}
}
创建Exchange、Queue并绑定
再实现RabbitAdmin后,我们就需要根据RabbitAdmin创建对应的交换机和队列,并建立绑定关系
package com.example.config.rabbitmq;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* 创建Queue、Exchange并建立绑定关系
* Created by shuai on 2019/5/16.
*/
@Configuration
public class MyRabbitMQCreateConfig {
@Resource(name = "v2RabbitAdmin")
private RabbitAdmin v2RabbitAdmin;
@Resource(name = "v1RabbitAdmin")
private RabbitAdmin v1RabbitAdmin;
@PostConstruct
public void RabbitInit() {
v2RabbitAdmin.declareExchange(new TopicExchange("exchange.topic.example.new", true, false));
v2RabbitAdmin.declareQueue(new Queue("queue.example.topic.new", true));
v2RabbitAdmin.declareBinding(
BindingBuilder
.bind(new Queue("queue.example.topic.new", true)) //直接创建队列
.to(new TopicExchange("exchange.topic.example.new", true, false)) //直接创建交换机 建立关联关系
.with("routing.key.example.new")); //指定路由Key
}
}
生产者
为了后续验证每个连接都建立成功,并且都能生产消息,生产者这里分别使用新生成的RabbitTemplate发送一条消息。
package com.example.topic;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class TopicProducer {
@Resource(name = "v1RabbitTemplate")
private RabbitTemplate v1RabbitTemplate;
@Resource(name = "v2RabbitTemplate")
private RabbitTemplate v2RabbitTemplate;
public void sendMessageByTopic() {
String content1 = "This is a topic type of the RabbitMQ message example from v1RabbitTemplate";
v1RabbitTemplate.convertAndSend(
"exchange.topic.example.new",
"routing.key.example.new",
content1);
String content2 = "This is a topic type of the RabbitMQ message example from v2RabbitTemplate";
v2RabbitTemplate.convertAndSend(
"exchange.topic.example.new",
"routing.key.example.new",
content2);
}
}
消费者
这里需要注意在配置消费队列时,需要标识ContainerFactory
package com.example.topic;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "queue.example.topic.new", containerFactory = "v2ContainerFactory")
public class TopicConsumer {
@RabbitHandler
public void consumer(String message) {
System.out.println(message);
}
}
这样就完成了SpringBoot连接多个RabbitMQ源的示例了,再写一段测试代码验证下。
测试验证
package com.example.test;
import com.example.topic.TopicProducer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitMQMultipleTest {
@Autowired
private TopicProducer topicProducer;
@Test
public void topicProducerTest() {
topicProducer.sendMessageByTopic();
}
}
执行测试代码,验证结果为:

验证SpringBoot连接多RabbitMQ源成功!
关注公众号:java之旅
springboot入门系列(五):SpringBoot连接多RabbitMQ源的更多相关文章
- SpringBoot入门(五)——自定义配置
本文来自网易云社区 大部分比萨店也提供某种形式的自动配置.你可以点荤比萨.素比萨.香辣意大利比萨,或者是自动配置比萨中的极品--至尊比萨.在下单时,你并没有指定具体的辅料,你所点的比萨种类决定了所用的 ...
- SpringBoot入门系列(转)
SpringBoot入门系列:第一篇 Hello World http://blog.csdn.net/lxhjh/article/details/51711148
- SpringBoot入门系列(十一)统一异常处理的实现
前面介绍了Spring Boot 如何整合定时任务已经Spring Boot 如何创建异步任务和定时任务.不清楚的朋友可以看看之前的文章:<Spring Boot 入门系列文章> 接下来主 ...
- SpringBoot入门系列(十二)统一日志收集
前面介绍了Spring Boot 异常处理,不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/1657780.html. 今 ...
- C语言高速入门系列(五)
C语言高速入门系列(五) C语言指针初涉 ------转载请注明出处:coder-pig 本节引言: 上一节我们对C ...
- vue 快速入门 系列 —— 侦测数据的变化 - [vue 源码分析]
其他章节请看: vue 快速入门 系列 侦测数据的变化 - [vue 源码分析] 本文将 vue 中与数据侦测相关的源码摘了出来,配合上文(侦测数据的变化 - [基本实现]) 一起来分析一下 vue ...
- SpringBoot入门系列~Spring-Data-JPA自动建表
1.pom.xml引入Spring-Data-Jpa和mysql依赖 <!-- Spring-data-jpa依赖 --> <dependency> <groupId&g ...
- springboot入门系列(二):SpringBoot整合Swagger
上一篇<简单搭建SpringBoot项目>讲了简单的搭建SpringBoot 项目,而 SpringBoot 和 Swagger-ui 搭配在持续交付的前后端开发中意义重大,Swagger ...
- Go语言入门系列(五)之指针和结构体的使用
Go语言入门系列前面的文章: Go语言入门系列(二)之基础语法总结 Go语言入门系列(三)之数组和切片 Go语言入门系列(四)之map的使用 1. 指针 如果你使用过C或C++,那你肯定对指针这个概念 ...
随机推荐
- 测试软件—禅道BUG管理工具
入禅 目录 入禅 1.禅道的基本使用 1.禅道的基本使用 admin(管理员) 部门:创建部门(需求部门,开发部门,测试部门,项目部门,产品部门) 组织:创建用户(产品经理,项目经理,开发人员,测试人 ...
- Scala的lazy应用
如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会起作用. 例如:对于特别耗时的的计算操作特别有用,如打开文件IO,网络IO等. import scala.io.Sourc ...
- golang defer 以及 函数栈和return
defer 作为延迟函数存在,在函数执行结束时才会正式执行,一般用于资源释放等操作 参考一段代码https://mp.weixin.qq.com/s/yfH0CBnUBmH0oxfC2evKBA来分析 ...
- 网络爬虫:利用selenium,pyquery库抓取并处理京东上的图片并存储到使用mongdb数据库进行存储
一,环境的搭建已经简单的工具介绍 1.selenium,一个用于Web应用程序测试的工具.其特点是直接运行在浏览器中,就像真正的用户在操作一样.新版本selenium2集成了 Selenium 1.0 ...
- BTRsys1~2系列靶机渗透
BTRsys系列靶机渗透 BTRsys1 端口发现加目录扫描. 发现目录:http://192.168.114.161/login.php 尝试弱密码失败,查看源代码. <script type ...
- 牛客在线习题:链表的k各节点翻转
题目描述 将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样你不能更改节点中的值,只能更改节点本身.要求空间复杂度 \ O ...
- thinkphp上传图片,生成缩略图
Image.php <?php /** * 实现图片上传,图片缩小, 增加水印 * 需要定义以下常量 * define('ERR_INVALID_IMAGE', 1); * define('ER ...
- CentOS7的下载及虚拟机的创建
一.CentOS的安装 1,首先打开开源镜像网站:www.mirrors.163.com(网易开源镜像网站),www.mirrors.aliyun.com(阿里云开源镜像网站) 以网易为例 2.点击进 ...
- 手把手撸套框架-Victory框架1.0 详解
目录 其实Victory框架1.0 在8月份就完成了,整个9月份都没有更新博客,主要还是因为松懈了. 所以,趁着国庆节的放假的时间把博客给更新一下,1.0总的来说算不得一个成熟的产品,但是拿来开发我们 ...
- 解决SpringBoot项目创建缓慢问题
SpringBoot项目构建缓慢 快速创建springboot项目 在创建一个springboot项目的时候,往往速度会很慢,原因是下载springboot文件的默认地址是springboot官网(国 ...