1 项目配置
1.1 pom.xml 配置依赖
<!-- RabbitMQ 启动依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- RabbitMQ测试依赖 -->
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
1.2 pojo实体类
package com.csdn.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
}
1.3 RabbitMQ的配置类
package com.csdn.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// RabbitMQ的配置类
@Configuration
public class RabbitMQConfig {
// 定制JSON格式的消息转化器
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
}
1.4 Service 层
package com.qf.service;
import org.springframework.stereotype.Service;
// RabbitMQ消息接收方处理消息的类
@Service
public class RabbitMQService {
}
1.5 application.yml 文件
# 配置RabbitMQ消息中间件连接配置
spring:
rabbitmq:
host: 192.168.93.100
port: 5672 # 编程端口(固定)
username: admin
password: 123
virtual-host: /zhangsan # 配置RabbitMQ虚拟主机路径(默认为"/"可以省略)
publisher-confirm-type: simple # 发送者开启确认机制
publisher-returns: true # 发送者开启return确认机制
2 Hello World(简单模式)
参考RabbitMQ官⽅⽂档,Hello World⼯作模式的流程示意图如下图所示。
RabbitMQ是⼀个消息代理:它接收和转发消息。你可以把它想象成⼀个邮局,当你把你想要寄的邮件放到⼀个邮 箱⾥,你可以确定邮递员先⽣或⼥⼠最终会把邮件送到你的收件⼈那⾥。在这个类⽐中,RabbitMQ是⼀个邮箱、 ⼀个邮局和⼀个邮递员。
应⽤场景:将发送的电⼦邮件放到消息队列,然后邮件服务在队列中获取邮件并发送给收件⼈。
2.1 Java代码实现
1.在RabbitMQ消息配置类RabbitMQConfig中,使⽤基于配置类的⽅式定制消息发送simple_queue_log组件。
@Bean
public Queue simpleQueueLog() {
return new Queue("simple_queue_log");
}
2.在RabbitMQService类中声明消息消费者,并监听simple_queue_log消息队列。
/** 简单模式消息接收,进⾏⽇志消息接收 */
@RabbitListener(queues = {"simple_queue_log"})
public void simpleConsumerLog(String message) {
System.out.println("接收到⽇志消息:" + message);
}
3.在测试类中使⽤RabbitTemplate模板类实现Hello World模式下的消息发送。
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void simplePublisher() {
rabbitTemplate.convertAndSend("simple_queue_log", "Hello World");
}
3 Work queues(⼯作队列模式)
参考RabbitMQ官⽅⽂档,Work queues⼯作模式的流程示意图如下图所示。
在Work queues⼯作模式中,不需要设置交换器(RabbitMQ会使⽤内部默认交换器进⾏消息转换),需要指定唯 ⼀的消息队列进⾏消息传递, 并且可以有多个消息消费者。在这种模式下,多个消息消费者通过轮询的⽅式依次接 收消息队列中存储的消息,⼀旦消息被某⼀个消费者接收,消息队列会将消息移除,⽽接收并处理消息的消费者必 须在消费完⼀条消息后再准备接收下⼀条消息。
应⽤场景:⼀般适⽤于执⾏资源密集型任务,单个消费者处理不过来,需要多个消费者进⾏处理。例如,⼀个订单 的处理需要5s,有多个订单可以同时放到消息队列,然后让多个消费者同时处理,这样就是并⾏了,⽽不是单个消 费者的串⾏情况。
3.1 Java代码实现
1.在RabbitMQ消息配置类RabbitMQConfig中,使⽤基于配置类的⽅式定制消息发送work_queue_order组件。
@Bean
public Queue workQueueOrder() {
return new Queue("work_queue_order");
}
2.在RabbitMQService类中声明两个消息消费者,都监听work_queue_order消息队列。
/** ⼯作队列模式消息接收 */
@RabbitListener(queues = {"work_queue_order"})
public void workConsumer01Order(String message) {
System.out.println("订单消息消费者1:" + message);
}
@RabbitListener(queues = {"work_queue_order"})
public void workConsumer02Order(String message) {
System.out.println("订单消息消费者2:" + message);
}
3.在测试类中使⽤RabbitTemplate模板类实现Work queues模式下的消息发送。
/** Work queues⼯作模式消息发送端 */
@Test
public void workPublisher() {
for (int i = 0; i < 6; i++) {
String orderId = UUID.randomUUID().toString();
rabbitTemplate.convertAndSend("work_queue_order", orderId);
}
}
4 Publish/Subscribe(发布订阅模式)
参考RabbitMQ官⽅⽂档,Publish/Subscribe⼯作模式的流程示意图如下图所示。
在Publish/Subscribe⼯作模式中,必须先配置⼀个fanout类型的交换器,不需要指定对应的路由键(Routing key),同时会将消息路由到每⼀个消息队列上,然后每个消息队列都可以对相同的消息进⾏接收存储,进⽽由各 ⾃消息队列关联的消费者进⾏消费。
应⽤场景:从上⾯的分析可以发现,Publish/Subscribe⼯作模式适⽤于进⾏相同业务功能处理的场合。
- 例如,⽤户注册成功后,需要同时发送邮件通知和短信通知,那么邮件服务消费者和短信服务消费者需要共同 消费“⽤户注册成功”这⼀条消息。
- 例如,更新商品库存后需要通知多个缓存和多个数据库,这⾥的结构应该是:⼀个fanout类型交换机扇出两 个消息队列,分别为缓存消息队列、数据库消息队列;⼀个缓存消息队列对应着多个缓存消费者,⼀个数据库 消息队列对应着多个数据库消费者。
4.1 Java代码实现
1.在消息接收和处理的业务类RabbitMQService中,使 ⽤@RabbitListener注解及其相关属性定制消息发送组件。
/** 使⽤基于注解的⽅式实现消息服务 */
// 1.1 Publish/Subscribe⼯作模式接收,处理邮件业务
@RabbitListener(bindings = @QueueBinding(
value = @Queue("fanout_queue_email"),
exchange = @Exchange(value = "fanout_exchange", type = "fanout")))// 指定当前消费者,类型为发布订阅模式
public void subConsumerEmailAno(User user) {
System.out.println("邮件业务接收到消息:" + user);
}
// 1.2 Publish/Subscribe⼯作模式接收,处理短信业务
@RabbitListener(bindings = @QueueBinding(
value = @Queue("fanout_queue_sms"),
exchange = @Exchange(value = "fanout_exchange", type = "fanout")))
public void subConsumerSmsAno(User user) {
System.out.println("短信业务接收到消息:" + user);
}
2.在测试类中使⽤RabbitTemplate模板类实现Work queues模式下的消息发送。
// 1.发布订阅模式,消息生产者生产消息
@Test
void subPublisher() {
User user = new User(1,"李红");
// 使用RabbitTemplate完成消息的发送:将消息指定发送给指定名称的交换机
// 参数1:将消息发送给哪一个交换机,
// 参数2:表示路由键
// 参数3:表示发送的消息数据是什么
rabbitTemplate.convertAndSend("fanout_exchange","",user);
}
5 Routing(路由模式)
参考RabbitMQ官⽅⽂档,Routing ⼯作模式的流程示意图如下图所示。
在Routing⼯作模式中,必须先配置⼀个direct类型的交换器,并指定不同的路由键值(Routing key)将对应的消 息从交换器路由到不同的消息队列进⾏存储,由消费者进⾏各⾃消费。
应⽤场景:从上⾯的分析可以发现,Routing⼯作模式适⽤于进⾏不同类型消息分类处理的场合。例如,⽇志收集 处理,⽤户可以配置不同的路由键值分别对不同级别的⽇志信息进⾏分类处理。
5.1 Java代码实现
1. 在消息接收和处理的业务类RabbitMQService中,使 ⽤@RabbitListener注解及其相关属性定制消息发送组件。
/** 路由模式消息接收,处理error级别⽇志信息 */
@RabbitListener(bindings = @QueueBinding(
value = @Queue("routing_queue_error"),
exchange = @Exchange(value = "routing_exchange", type = "direct"),
key = "error_routing_key"))
public void routingConsumerError(String message) {
System.out.println("接收到error级别⽇志消息:" + message);
}
/** 路由模式消息接收,处理info、error、warning级别⽇志信息 */
@RabbitListener(bindings = @QueueBinding(
value = @Queue("routing_queue_all"),
exchange = @Exchange(value = "routing_exchange", type = "direct"),
key = {"error_routing_key", "info_routing_key", "warning_routing_key"}))
public void routingConsumerAll(String message) {
System.out.println("接收到info、error、warning等级别⽇志消息:" + message);
}
2.在测试类中使⽤RabbitTemplate模板类实现Work queues模式下的消息发送。
/** Routing路由模式消息发送端 */
@Test
public void routingPublisher() {
rabbitTemplate.convertAndSend("routing_exchange", "error_routing_key", "路由模式发送error消息");
}
6 Topics(主题模式)
参考RabbitMQ官⽅⽂档,Topics⼯作模式的流程示意图如下图所示。
在Topics⼯作模式中,必须先配置⼀个topic类型的交换器,并指定不同的路由键值(Routing key)将对应的消息 从交换器路由到不同的消息队列进⾏存储,然后由消费者进⾏各⾃消费。Topics模式与Routing模式的主要不同在 于:Topics模式设置的路由键是包含通配符的,其中,#匹配零或多个字符,*匹配⼀个字符,然后与其他字符⼀起 使⽤“.”进⾏连接,从⽽组成动态路由键,在发送消息时可以根据需求设置不同的路由键,从⽽将消息路由到不同的 消息队列。
应⽤场景:通常情况下,Topics⼯作模式适⽤于根据不同需求动态传递处理业务的场合。例如,⼀些订阅客户只接 收邮件消息,⼀些订阅客户只接收短信消息,那么可以根据客户需求进⾏动态路由匹配,从⽽将订阅消息分发到不 同的消息队列中。
6.1 Java代码实现
1. 在消息接收和处理的业务类RabbitMQService中,使 ⽤@RabbitListener注解及其相关属性定制消息发送组件。
/**
* 通配符模式消息接收,进⾏邮件业务订阅处理
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic_queue_email"),
exchange = @Exchange(value = "topic_exchange", type = "topic"),
key = "info.#.email.#"))
public void topicConsumerEmail(String message) {
System.out.println("接收到邮件订阅需求处理消息:" + message);
}
/**
* 通配符模式消息接收,进⾏短信业务订阅处理
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic_queue_sms"),
exchange = @Exchange(value = "topic_exchange", type = "topic"),
key = "info.#.sms.#"))
public void topicConsumerSms(String message) {
System.out.println("接收到短信订阅需求处理消息:" + message);
}
2.在测试类中使⽤RabbitTemplate模板类实现Work queues模式下的消息发送。
/** Topics主题模式消息发送端 */
@Test
public void topicPublisher() {
rabbitTemplate.convertAndSend("topic_exchange", "info.email", "通配符模式发送email消
息");
}
7 RPC远程过程调⽤模式
参考RabbitMQ官⽅⽂档,RPC⼯作模式的流程示意图如下图所示。
RPC⼯作模式与Work queues⼯作模式主体流程相似,都不需要设置交换器,需要指定唯⼀的消息队列进⾏消息传 递。RPC模式与Work queues模式的主要不同在于:RPC模式是⼀个回环结构,主要针对分布式架构的消息传递业 务,客户端Client先发送消息到消息队列,远程服务端Server获取消息,然后再写⼊另⼀个消息队列,向原始客户 端Client响应消息处理结果。
应⽤场景:从上⾯的分析可以发现,RPC⼯作模式适⽤于远程服务调⽤的业务处理场合。
- 例如,在分布式架构中必须考虑的分布式事务管理问题。
- 例如,在远程计算机上运⾏功能,需要等待接⼝返回数据,如订单⽀付。
8 Publisher Confirms 发布者确认模式
Publisher confirms是RabbitMQ扩展,以实现可靠的发布。当在通道上启⽤发布者确认时,客户端发布的消息将 由代理异步确认,这意味着它们已在服务器端得到处理。
应⽤场景:对于消息可靠性要求较⾼,⽐如钱包扣款。
8.1 Java代码部分实现
1. PublisherConfirmAndReturnConfig 类实现
package com.csdn.config;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* RabbitMQ 消息确认机制使用相关的接口:都是RabbitTemplate类提供的两个接口
*
*/
@Component
public class PublisherConfirmAndReturnConfig implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init(){
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnsCallback(this);
}
// 该方法 RabbitTemplate.ConfirmCallback 中的方法
/**
* 如果消息被正常发送到交换机,则会调用该方法(自动回调)
* @param correlationData 相关数据,对象中又一个id的属性,用来表示消息的唯一标识
* @param ack 表示当前消息投放到交换机的状态,true表示投放成功
* @param s 表示投送失败的原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
if(ack) {
System.out.println("消息给交换机发送成功!");
}else {
System.err.println("消息给交换机发送失败!");
}
}
// 该方法 RabbitTemplate.ReturnsCallback 中的方法
/**
* 如果消息从交换机失败的被发送到队列,则回调该方法(自动回调)
* @param returnedMessage 该参数表示返回的消息内容,常见包含一下消息:
* - message:发送的消息内容
* - replyCode:回应码
* - replyText:回应内容
* - exchange:交换机
* - routingKey:路由键
*/
@Override
public void returnedMessage(ReturnedMessage returnedMessage) {
System.err.println("消息从交换机到队列中发送失败!");
}
}
2.在测试类中使⽤RabbitTemplate模板类实现Work queues模式下的消息发送。(随便发送一个)