RabbitMQ 结合 SpringAMQP 基本用法
文章目录
SpringAMQP
Spring AMQP是Spring框架提供的一个基于AMQP(高级消息队列协议)的消息队列解决方案,用于简化Spring应用程序对消息队列的使用。它主要包含以下几个模块:
- spring-amqp:该模块是Spring AMQP的核心模块,定义了与AMQP相关的通用操作,如发送消息、接收消息等。
- spring-rabbit:该模块是基于RabbitMQ的消息中间件,它提供了模板化的发送和接收消息的抽象层,简化了RabbitMQ的使用。
- spring-erlang:该模块是基于Erlang的消息中间件,它提供了与RabbitMQ的交互方式,方便使用Erlang语言的开发者使用Spring AMQP。
Spring AMQP的主要优点在于它提供了一个高级别的抽象,使得生产者和消费者可以用简单的方式与消息队列进行通信,同时减少了开发者对AMQP协议的细节处理。此外,Spring AMQP还支持多种消息传递模式,如发布/订阅、点对点、请求/响应等。
支持范围
Spring AMQP支持多种消息队列,包括但不限于以下几种:
- RabbitMQ:一个基于AMQP标准、开放源代码的、可移植的、分布式的消息代理软件。RabbitMQ是使用Erlang语言编写的一个开源消息代理软件,它实现了AMQP协议,提供了多种语言的客户端库。
- ActiveMQ:一个流行的基于Java的消息传递系统,它实现了JMS(Java消息服务)规范以及其他AMQP标准。ActiveMQ具有高度可靠性和灵活性,支持多种消息协议和数据传输格式。
- Apache Kafka:一个开源的分布式流处理系统,它以高吞吐量、可扩展性和实时性著称。Apache Kafka通常被用于处理和分析大规模的数据流,但它也可以作为消息队列使用。
- Amazon SQS:亚马逊云服务中的简单队列服务(Simple Queue Service),它是一个分布式消息队列系统,可以在多个亚马逊EC2实例之间安全地传递消息。
以上是一些常见的消息队列,Spring AMQP可以与这些消息队列进行集成,帮助开发者更方便地使用这些消息队列进行应用程序的消息传递。
pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
配置文件
spring:
rabbitmq:
host: 127.0.0.1 # ip
port: 5672 # 端口
username: root # 用户名
password: root # 密码
virtural-host: / # 虚拟地址
listener:
simple:
prefetch: 1 # 设置这个和值 可以控制预取到消息的上限 这里默认是无限
- 消费预取限制
listener:
simple:
prefetch: 1 # 设置这个和值 可以控制预取到消息的上限 这里默认是无限
交换机
如果不加入交换机 默认被消费者消费之后就会从消息队列中删除,可以投递给多个队列,这样就解决了一次发送,多次接收的问题
分为以下几类:
- Fanout 广播
- Direct 路由
- Topic 话题
FanoutExchange(广播模式)最简单!
- 在springAMQP中提供了生命交换机、队列、绑定关系的API
1、添加配置类
在consumer服务声明EXchange、Queue、Binding
在consumer服务常见一个类 添加@Configuration注解, 并声明FanoutExchange,Queue 和绑定关系对象Binding,代码如下:
@Configuration
public class FanoutConfig{
// 声明 FanoutExchange 交换机
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("zky.fanout");
}
// 声明 队列1
@Bean
public Queue fanoutQueue1(){
return new Queue("fanout.queue");
}
// 绑定 队列1 和 交换机
@Bean
public Binding fanoutBinding1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
// 声明 队列2
@Bean
public Queue fanoutQueue1(){
return new Queue("fanout.queue");
}
// 绑定 队列2 和 交换机
@Bean
public Binding fanoutBinding1(Queue fanoutQueue2, FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
}
2、消息发送
public void sendFanoutExchange(){
// 交换机名称
String exchangeName = "zky.fanout";
// 消息内容
String message = "hello, everyone!"
// 发送消息
rabbitTemplate.convertAndSend(exchangeName,"", message);
}
3、消息接收
@RabbitListener(queues = "fanout.queue1")
public void listentFanoutQueue1(String msg){
System.out.println("消费者收到fanout.queue1的消息:" + msg);
}
@RabbitListener(queues = "fanout.queue2")
public void listentFanoutQueue2(String msg){
System.out.println("消费者收到fanout.queue2的消息:" + msg);
}
DirectExchange(路由模式)
发布给指定的Queue 因此叫做路由模式
-
每一个Queue都与Exchange设置一个BingdingKey
-
发布者发送消息是,指定消息的RoutingKey
-
Exchange将消息路由到BindingKey与消息RoutingKey一致的队列
分为以下几个步骤:
1、利用@RabbitListener 声明Exchange、Queue、RoutingKey
2、在consumer服务中,编写两个消费者方法,分别监听direct.queue1 和 direct.queue2
3、在publisher 中编写测试方法,向 zky.direct 发送消息[[]]
1、消息接收
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue1"),
exchange = @Exchange(name = "zky.direct", type = ExchangeTypes.DIRECT),
key = {"red", "blue"}
))
public void listenDirectQueue1(String msg){
System.out.println("消费者收到fanout.queue1的消息:" + msg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "direct.queue2"),
exchange = @Exchange(name = "zky.direct", type = ExchangeTypes.DIRECT),
key = {"yellow", "red"}
))
public void listenDirectQueue2(String msg){
System.out.println("消费者收到fanout.queue2的消息:" + msg);
}
2、消息发送
public void sendDirectExchange(){
// 交换机名称
String exchangeName = "zky.fanout";
// 消息内容
String message = "hello, blue!"
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "blue", message);
}
TopicExchange(话题模式)
和directExchange 模式类似,区别在于routingKey 必须是多个单词组成的列表,并且以 . 分割
例如:china.news
china.weather
…
Queue与Exchange指定BindingKey时可以使用通配符:
#: 代指0或多个单词
*: 代指一个单词
1、消息发送
public void sendTopicExchange(){
// 交换机名称
String exchangeName = "zky.topic";
// 消息内容
String message = "你好, 中国!"
// 发送消息
rabbitTemplate.convertAndSend(exchangeName, "china.news", message);
}
2、消息接收
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "zky.topic", type = ExchangeTypes.TOPIC),
key = "china.#"
))
public void listenDirectQueue1(String msg){
System.out.println("消费者收到topic.queue1的消息:" + msg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = "topic.queue2"),
exchange = @Exchange(name = "zky.topic", type = ExchangeTypes.TOPIC),
key = "#.news"
))
public void listenDirectQueue2(String msg){
System.out.println("消费者收到topic.queue2的消息:" + msg);
}
消息转换器
@Bean
public Queue objectQueue(){
return new Queue("objectQueue");
}
public void sendObjectQueue(){
Map<String,Object> map = new HashMap<>();
msg.put("name", "鸽鸽");
msg.put("age", "21")
rabbitTemplate.convertAndSend("object.queue", msg);
}
序列化性能优化
Spring 的对消息对象的处理是由 org.springframework.amqp.support.converter.MessageConverter来处理的,而默认实现是SimpleMessageConverter 基于JDK 的ObjectOutputStream 完成序列化
如果要修改只需要定义一个MessageConverter 类型的Bean 即可,推荐用JSON方式序列化 applicaton/json 格式,步骤如下:
引入依赖
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.10</version>
</dependency>
</dependencies>
声明Bean
- 服务声明MessageConvert 在amqp包下面啊!
@Bean
public MessageConverter jsonMessageConverter(){
return new Jackson2JsonMessageConverter();
}
发送消息(不用变)
接收消息
@RabbitListener(queues = "obejct.queue")
public void listenerObjectQueue(Map<String, Obejct> map){
System.out.println("消费者收到obejct.queue的消息:" + map);
}
RabbitMQ 高级特性
消息确认、消息可靠投递、备份交换机、消息幂等性保障、自定义消费者、消费端限流、ack超时重传机制、TTL队列/消息、死信队列、延迟队列、优先级、持久化
总之就是保持消息的可靠传输