spring boot 2.x 系列 —— spring boot 整合 RabbitMQ
文章目录
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all
一、 项目结构说明
1.1 这里采用maven多模块的构建方式,在spring-boot-rabbitmq下构建三个子模块:
- rabbitmq-common 是公共模块,用于存放公共的接口、配置和bean,被rabbitmq-producer和rabbitmq-consumer在pom.xml中引用;
- rabbitmq-producer 是消息的生产者模块;
- rabbitmq-consumer是消息的消费者模块。
1.2 关于rabbitmq安装、交换机、队列、死信队列等基本概念可以参考我的手记《RabbitMQ实战指南》读书笔记,里面有详细的配图说明。

二、关键依赖
在父工程的项目中统一导入依赖rabbitmq的starter(spring-boot-starter-amqp),父工程的pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>rabbitmq-consumer</module>
<module>rabbitmq-producer</module>
<module>rabbitmq-common</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.heibaiying</groupId>
<artifactId>spring-boot-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-rabbitmq</name>
<description>RabbitMQ project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<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>
</project>
三、公共模块(rabbitmq-common)
- bean 下为公共的实体类。
- constant 下为公共配置,用静态常量引用。(这里我使用静态常量是为了方便引用,实际中也可以按照情况,抽取为公共配置文件)

package com.heibaiying.constant;
/**
* @author : heibaiying
* @description : rabbit 公用配置信息
*/
public class RabbitInfo {
// queue 配置
public static final String QUEUE_NAME = "spring.boot.simple.queue";
public static final String QUEUE_DURABLE = "true";
// exchange 配置
public static final String EXCHANGE_NAME = "spring.boot.simple.exchange";
public static final String EXCHANGE_TYPE = "topic";
// routing key
public static final String ROUTING_KEY = "springboot.simple.*";
}
四、服务消费者(rabbitmq-consumer)

4.1 消息消费者配置
spring:
rabbitmq:
addresses: 127.0.0.1:5672
# RabbitMQ 默认的用户名和密码都是guest 而虚拟主机名称是 "/"
# 如果配置其他虚拟主机地址,需要预先用管控台或者图形界面创建 图形界面地址 http://主机地址:15672
username: guest
password: guest
virtual-host: /
listener:
simple:
# 为了保证信息能够被正确消费,建议签收模式设置为手工签收,并在代码中实现手工签收
acknowledge-mode: manual
# 侦听器调用者线程的最小数量
concurrency: 10
# 侦听器调用者线程的最大数量
max-concurrency: 50
4.2 使用注解@RabbitListener和@RabbitHandler创建消息监听者
- 使用注解创建的交换机、队列、和绑定关系会在项目初始化的时候自动创建,但是不会重复创建;
- 这里我们创建两个消息监听器,分别演示消息是基本类型和消息是对象时的配置区别。
/**
* @author : heibaiying
* @description : 消息是对象的消费者
*/
@Component
@Slf4j
public class RabbitmqBeanConsumer {
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = RabbitBeanInfo.QUEUE_NAME, durable = RabbitBeanInfo.QUEUE_DURABLE),
exchange = @Exchange(value = RabbitBeanInfo.EXCHANGE_NAME, type = RabbitBeanInfo.EXCHANGE_TYPE),
key = RabbitBeanInfo.ROUTING_KEY)
)
@RabbitHandler
public void onMessage(@Payload Programmer programmer, @Headers Map<String, Object> headers, Channel channel) throws Exception {
log.info("programmer:{} ", programmer);
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
channel.basicAck(deliveryTag, false);
}
}
@Component
@Slf4j
public class RabbitmqConsumer {
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = RabbitInfo.QUEUE_NAME, durable = RabbitInfo.QUEUE_DURABLE),
exchange = @Exchange(value = RabbitInfo.EXCHANGE_NAME, type = RabbitInfo.EXCHANGE_TYPE),
key = RabbitInfo.ROUTING_KEY)
)
@RabbitHandler
public void onMessage(Message message, Channel channel) throws Exception {
MessageHeaders headers = message.getHeaders();
// 获取消息头信息和消息体
log.info("msgInfo:{} ; payload:{} ", headers.get("msgInfo"), message.getPayload());
// DELIVERY_TAG 代表 RabbitMQ 向该Channel投递的这条消息的唯一标识ID,是一个单调递增的正整数
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
// 第二个参数代表是否一次签收多条,当该参数为 true 时,则可以一次性确认 DELIVERY_TAG 小于等于传入值的所有消息
channel.basicAck(deliveryTag, false);
}
}
五、 消息生产者(rabbitmq-producer)

5.1 消息生产者配置
spring:
rabbitmq:
addresses: 127.0.0.1:5672
# RabbitMQ 默认的用户名和密码都是guest 而虚拟主机名称是 "/"
# 如果配置其他虚拟主机地址,需要预先用管控台或者图形界面创建 图形界面地址 http://主机地址:15672
username: guest
password: guest
virtual-host: /
# 是否启用发布者确认 具体确认回调实现见代码
publisher-confirms: true
# 是否启用发布者返回 具体返回回调实现见代码
publisher-returns: true
# 是否启用强制消息 保证消息的有效监听
template.mandatory: true
server:
port: 8090
5.2 创建消息生产者
/**
* @author : heibaiying
* @description : 消息生产者
*/
@Component
@Slf4j
public class RabbitmqProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendSimpleMessage(Map<String, Object> headers, Object message,
String messageId, String exchangeName, String key) {
// 自定义消息头
MessageHeaders messageHeaders = new MessageHeaders(headers);
// 创建消息
Message<Object> msg = MessageBuilder.createMessage(message, messageHeaders);
/* 确认的回调 确认消息是否到达 Broker 服务器 其实就是是否到达交换器
如果发送时候指定的交换器不存在 ack就是false 代表消息不可达 */
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
log.info("correlationData:{} , ack:{}", correlationData.getId(), ack);
if (!ack) {
System.out.println("进行对应的消息补偿机制");
}
});
/* 消息失败的回调
* 例如消息已经到达交换器上,但路由键匹配任何绑定到该交换器的队列,会触发这个回调,此时 replyText: NO_ROUTE
*/
rabbitTemplate.setReturnCallback((message1, replyCode, replyText, exchange, routingKey) -> {
log.info("message:{}; replyCode: {}; replyText: {} ; exchange:{} ; routingKey:{}",
message1, replyCode, replyText, exchange, routingKey);
});
// 在实际中ID 应该是全局唯一 能够唯一标识消息 消息不可达的时候触发ConfirmCallback回调方法时可以获取该值,进行对应的错误处理
CorrelationData correlationData = new CorrelationData(messageId);
rabbitTemplate.convertAndSend(exchangeName, key, msg, correlationData);
}
}
5.3 以单元测试的方式发送消息
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqProducerTests {
@Autowired
private RabbitmqProducer producer;
/***
* 发送消息体为简单数据类型的消息
*/
@Test
public void send() {
Map<String, Object> heads = new HashMap<>();
heads.put("msgInfo", "自定义消息头信息");
// 模拟生成消息ID,在实际中应该是全局唯一的 消息不可达时候可以在setConfirmCallback回调中取得,可以进行对应的重发或错误处理
String id = String.valueOf(Math.round(Math.random() * 10000));
producer.sendSimpleMessage(heads, "hello Spring", id, RabbitInfo.EXCHANGE_NAME, "springboot.simple.abc");
}
/***
* 发送消息体为bean的消息
*/
@Test
public void sendBean() {
String id = String.valueOf(Math.round(Math.random() * 10000));
Programmer programmer = new Programmer("xiaoMing", 12, 12123.45f, new Date());
producer.sendSimpleMessage(null, programmer, id, RabbitBeanInfo.EXCHANGE_NAME, RabbitBeanInfo.ROUTING_KEY);
}
}
六、项目构建的说明
因为在项目中,consumer和producer模块均依赖公共模块,所以在构建consumer和producer项目前需要将common 模块安装到本地仓库,依次对父工程和common模块执行:
mvn install -Dmaven.test.skip = true
consumer中 pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.heibaiying</groupId>
<artifactId>spring-boot-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>rabbitmq-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rabbitmq-consumer</name>
<description>RabbitMQ consumer project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.heibaiying</groupId>
<artifactId>rabbitmq-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
producer中 pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.heibaiying</groupId>
<artifactId>spring-boot-rabbitmq</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>rabbitmq-producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>rabbitmq-producer</name>
<description>RabbitMQ producer project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.heibaiying</groupId>
<artifactId>rabbitmq-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
附:源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all
spring boot 2.x 系列 —— spring boot 整合 RabbitMQ的更多相关文章
- spring boot实战(第十二篇)整合RabbitMQ
前言 最近几篇文章将围绕消息中间件RabbitMQ展开,对于RabbitMQ基本概念这里不阐述,主要讲解RabbitMQ的基本用法.Java客户端API介绍.spring Boot与RabbitMQ整 ...
- spring boot 2.x 系列 —— spring boot 整合 redis
文章目录 一.说明 1.1 项目结构 1.2 项目主要依赖 二.整合 Redis 2.1 在application.yml 中配置redis数据源 2.2 封装redis基本操作 2.3 redisT ...
- spring boot 2.x 系列 —— spring boot 整合 druid+mybatis
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.说明 1.1 项目结构 项目查询用的表对应的建表语句放置在resour ...
- spring boot 2.x 系列 —— spring boot 整合 servlet 3.0
文章目录 一.说明 1.1 项目结构说明 1.2 项目依赖 二.采用spring 注册方式整合 servlet 2.1 新建过滤器.监听器和servlet 2.2 注册过滤器.监听器和servlet ...
- spring boot 2.x 系列 —— spring boot 整合 kafka
文章目录 一.kafka的相关概念: 1.主题和分区 2.分区复制 3. 生产者 4. 消费者 5.broker和集群 二.项目说明 1.1 项目结构说明 1.2 主要依赖 二. 整合 kafka 2 ...
- spring boot 2.x 系列 —— spring boot 整合 dubbo
文章目录 一. 项目结构说明 二.关键依赖 三.公共模块(boot-dubbo-common) 四. 服务提供者(boot-dubbo-provider) 4.1 提供方配置 4.2 使用注解@Ser ...
- spring boot 2.x 系列 —— spring boot 实现分布式 session
文章目录 一.项目结构 二.分布式session的配置 2.1 引入依赖 2.2 Redis配置 2.3 启动类上添加@EnableRedisHttpSession 注解开启 spring-sessi ...
- 2018年分享的Spring Cloud 2.x系列文章
还有几个小时2018年就要过去了,盘点一下小编从做做公众号以来发送了273篇文章,其中包含原创文章90篇,虽然原创的有点少,但是2019年小编将一如既往给大家分享跟多的干货,分享工作中的经验,让大家在 ...
- spring boot&&cloud干货系列
接触spring boot也有些时日了,刚开始博主还想参照官方参考指南自己写一个系列的入门式的教程,包含spring boot的所有模块的用法,后来发现,有一大波优秀的系列文章和项目了,所以就没班门弄 ...
随机推荐
- exponential family distribution(指数族分布)
1. exponential family 给定参数 η,关于 x 的指数族分布定义为如下的形式: p(x∣∣η)=h(x)g(η)exp{ηTu(x)} 其中 x 可以为标量也可以为矢量,可以为离散 ...
- 清晰明亮的白色lua协程(coroutine)
协同程序线程类和多线程下似:它有它自己的堆栈.自己的局部变量.它有自己的指令指针,但是,其他协程共享全局变量和其他项目信息.主要不同在于:多处理器的情况下.概念上来说多线程是同一时候执行多个线程,而协 ...
- QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度复制)非常实用
FROM:http://apps.hi.baidu.com/share/detail/33517814 今天做项目时,需要用到QList来存储一组点.为此,我对QList类的说明进行了如下翻译. QL ...
- CCD 与 CMOS
窗帘快门与全局快门: 窗帘快门,每次只允许一条缝的光线摄入,因此会呈现自上而下的扫描式拍摄,也就意味着画面上的不同高度,其实拍摄的时间是不同的,也就进一步造成了在高速移动的火车上,如果拍摄窗外的景物, ...
- 追本溯源 —— 句型、表达、模式,pattern,著名的话
** 时候,做了 ** 事,是我 **,做得最对的一件事: "Winning that ticket was the best thing that ever happened to me& ...
- Cocos2d-x layout (两)
相对于对照布局 Size widgetSize = Director::getInstance()->getWinSize(); Text* alert = Text::create(" ...
- C++ Primer Plus的若干收获--(十一)
本篇主要讲了转换函数的利与弊以及简要介绍流与iostream文件 因为在本篇仍然要使用上篇的Stonewt类,这里首先给出其代码 <span style="font-size:18px ...
- 參数传递(引用,指针,值传递)C++11
C++中,函数的參数传递方式有值传递.地址传递.传地址有指针和引用方式. 在函数參数中,传地址的理由有: 1.使被调函数能够改动主调函数中的数据对象: 2.传地址能够降低数据拷贝,提高程序运行速度. ...
- c#调api串口通讯
原文:c#调api串口通讯 在调试ICU通信设备的时候,由于串口通信老出现故障,所以就怀疑CF实现的SerialPort类是否有问题,所以最后决定用纯API函数实现串口读写. 先从网上搜索相关代码(关 ...
- crossplatform---Nodejs in Visual Studio Code 02.学习Nodejs
1.开始 源码下载:https://github.com/sayar/NodeMVA 在线视频:https://mva.microsoft.com/en-US/training-courses/usi ...