Spring Boot RabbitMQ 应用场景
1. 前言
消息队列是一个容器,可以对程序产生的消息进行存储。消息队列的主要用途是削峰、异步、解耦,我们用一个实际场景来解释下。
有一家果汁生产企业,张三是采购员,负责采购水果;李四、赵五是配送员,分别负责将苹果、香蕉配送到生产车间。
1.1 削峰
传统模式下,张三采购完成,回到公司后,联系李四、赵五配送采购的水果。但是随着公司业务量大增,张三一次性采购的水果,李四、赵五得需要几天才能配送完。所以需要一个仓库,张三采购完成直接放到仓库里,李四、赵五慢慢从仓库取出配送。
此处的仓库就是消息队列,张三是采购消息的生产者,李四、赵五是消费者。当生产的消息太多时,可以使用队列削峰
,这样消费者可以慢慢处理消息。
1.2 异步
传统模式下,张三采购完成后,需要等待李四、赵五来取,实际上极大浪费了张三的时间。如果直接放入仓库,可以不必等待,直接进行下面的工作。也就是说,张三与李四、赵五的工作是异步
的,减少了等待时间。
1.3 解耦
之前张三采购完成后,有责任通知李四、赵五来取。万一李四、赵五忘带手机,张三还得联系领导协调处理,说实话张三就是个大老粗,整天为这些破事烦得不行。
如果直接放入仓库,张三根本不用管李四、赵五的事情,感觉愉快极了。张三与李四、赵五的工作不再互相依赖,都变得更加简单了,这就是解耦
。
2. RabbitMQ 简介
RabbitMQ 是非常出名的消息中间件,遵循 AMQP 协议,可以跨平台、跨语言使用。 RabbitMQ 具备低时延、高可用的特点,还有简洁易用的可视化管理界面,所以本节我们使用 RabbitMQ 来进行消息队列技术的演示。
3. Spring Boot 实现
我们就针对上面的场景,使用 Spring Boot ,结合 RabbitMQ 来具体实现下水果采购、配送的管理。
3.1 使用 Spring Initializr 创建项目
Spring Boot 版本选择 2.2.5 ,Group 为 com.5axxw , Artifact 为 spring-boot-rabbitmq,生成项目后导入 Eclipse 开发环境。
3.2 引入项目依赖
我们引入 Web 项目依赖与 AMQP 消息队列依赖。
实例:
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- AMQP 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
3.3 配置 RabbitMQ 连接信息
项目创建后,通过 applicaiton.properties 配置 RabbitMQ 的链接信息。
实例:
#地址
spring.rabbitmq.host=127.0.0.1
#端口 默认5672
spring.rabbitmq.port=5672
#用户名
spring.rabbitmq.username=guest
#密码
sprng.rabbitmq.password=guest
3.4 配置队列
首先配置两个队列,存储苹果采购消息、香蕉采购消息。
实例:
/**
* 消息队列配置类
*/
@Configuration
public class RabbitConfig {
/**
* 苹果采购消息队列
*/
@Bean
public Queue appleQueue() {
return new Queue("apple-queue");
}
/**
* 香蕉采购消息队列
*/
@Bean
public Queue bananaQueue() {
return new Queue("banana-queue");
}
}
3.5 配置交换机和绑定
如果消息直接发到队列的话,不够灵活, RabbitMQ 提供了交换机与绑定机制。
消息发送给交换机,交换机可以灵活地与队列进行绑定,这样消息就可以通过多种方式进入队列了。
实例:
/**
* 配置交换机
*/
@Bean
TopicExchange exchangeTopic() {
return new TopicExchange("exchange-topic");
}
/**
* 交换机绑定苹果采购消息队列
*/
@Bean
Binding bindAppleQueue() {
return BindingBuilder.bind(appleQueue()).to(exchangeTopic()).with("#.apple.#");
}
/**
* 交换机绑定香蕉采购消息队列
*/
@Bean
Binding bindBananaQueue() {
return BindingBuilder.bind(bananaQueue()).to(exchangeTopic()).with("#.banana.#");
}
我们来详细解释下交换机与绑定的运行机制。
- 我们配置了一个交换机 exchangeTopic ,它可以接收消息。
- 交换机 exchangeTopic 绑定了两个队列,分别是 appleQueue 和 bananaQueue ,说明这两个队列在关注该交换机收到的消息。
- 那么交换机 exchangeTopic 收到的消息到底会进入哪个队列呢,我们发现交换机的类型是
TopicExchange
,说明该交换机是话题
交换机,队列应该是获取其感兴趣的话题相关的消息。 - 当 appleQueue 队列绑定到交换机时,
with("#.apple.#")
就表示 appleQueue 关心的是 apple 相关的话题;而 bananaQueue 关心的是 banana 相关的话题。 - 所以可以推断出,消息在发送时,可以指定话题相关的信息,以便消息能被关注该话题的队列接收。
经过上面的分析,我们就知道了消息发送时通过携带话题信息,交换机会将该消息路由到关心该话题的队列中。
3.6 创建消费者
接下来,我们就可以定义消息的消费者李四、赵五了。他俩分别关心苹果采购消息和香蕉采购消息。也就是监听苹果消息队列和香蕉消息队列。
实例:
/**
* 消息队列接收
*/
@Component
public class RabbitReceiver {
/**
* lisi负责监听apple-queue
*/
@RabbitListener(queues = "apple-queue")
public void lisi(String msg) {
System.out.println("李四知道:" + msg);
}
/**
* zhaowu负责监听banana-queue
*/
@RabbitListener(queues = "banana-queue")
public void zhaowu(String msg) {
System.out.println("赵五知道:" + msg);
}
}
3.7 测试
运行启动类,从 RabbitMQ 管理界面可以看到已生成指定名称的队列了。
此时我们定义一个控制器用于发起测试,直接使用 rabbitTemplate 发送消息即可。
实例:
@RestController
public class TestController {
@Autowired
private RabbitTemplate rabbitTemplate;
@GetMapping("/test")
public void test() {
// 发送消息 参数分别为:交换机名称、路由键、消息内容
rabbitTemplate.convertAndSend("exchange-topic", "apple", "苹果来了10斤");
rabbitTemplate.convertAndSend("exchange-topic", "banana", "香蕉来了5斤");
rabbitTemplate.convertAndSend("exchange-topic", "apple.banana", "苹果来了8斤;香蕉来了20斤");
}
}
convertAndSend() 方法的第 1 个参数表示交换机,第 2 个参数表示路由键(消息的话题),第 3 个是消息内容。
所以第 1 个消息会被 apple-queue 接收,第 2 个消息会被 banana-queue 接收,第 3 个消息会被两个队列接收。
我们启动项目,然后访问 http://127.0.0.1:8080/test
,控制台输出如下,验证成功。
赵五知道:香蕉来了5斤
李四知道:苹果来了10斤
赵五知道:苹果来了8斤;香蕉来了20斤
李四知道:苹果来了8斤;香蕉来了20斤
4. 小结
本小节通过一个实际应用场景,演示了 Spring Boot 中使用 RabbitMQ 消息队列的方法。
至此, Spring Boot 的内容就全部结束了。纸上得来终觉浅,绝知此事要躬行。任何的实用技能都需要在不断练习与使用中感悟、完善、提升, Spring Boot 也不例外。
所以还没有使用 Spring Boot 的朋友,抓紧上手吧!