发布订阅模式
必须先配置一 个fanout类型的交换器,不需要指定对应的路由 键(Routing key),同时会将消息路由到每一 个消息队列上,然后每个消息队列都可以对相同 的消息进行接收存储,进而由各自消息队列关联 的消费者进行消费
- 添加依赖,在SpriingBoot项目中的pom.xml中加入RabbitMQ相关依赖,以便使用RabbitMQ功能
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- 在application.properties中配置RabbitMQ连接信息,包括RabbitMQ的地址、端口、用户名、密码等基本信息
ini
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.publisher-confirm-type=simple
simple模式表示使用简单的确认模式,当消息被成功处理后,RabbitMQ 会发送一个确认信号。这个配置能够帮助开发者确认消息是否已经成功发布。
spring.rabbitmq.listener.simple.concurrency=3
该配置项用于配置监听器的最小并发数。意思是启动时至少会有 3 个消费者线程来处理 RabbitMQ 队列中的消息。
spring.rabbitmq.listener.simple.max-concurrency=10
该配置项用于设置监听器的最大并发数。意思是监听器可以在负载较高时,最多同时启动 10 个消费者线程来消费消息
- 创建连接工厂(RabbitConnectionFactoryBean)
ConnectionFactory
是 RabbitMQ 连接的核心,它负责创建与 RabbitMQ 服务器的连接。Spring Boot 自动配置了 ConnectionFactory
,因此通常不需要手动创建连接工厂。
RabbitTemplate
是 Spring AMQP 用来发送消息的核心类。Spring Boot 会自动配置一个 RabbitTemplate
@RabbitListener
注解来监听 RabbitMQ 消息队列,Spring Boot 会自动配置 RabbitListenerContainerFactory
。
如果需要更多的自定义配置,可以通过 RabbitConnectionFactoryBean
或者 ConnectionFactory
接口手动配置连接工厂,并在配置类中将其作为 @Bean
注入。
- 定义交换机、队列、绑定: 创建 RabbitMQ 交换机(Exchange)、队列(Queue)和它们之间的绑定(Binding)。
typescript
AmqpAdmin管理类配置方法
package com.xyu;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
@SpringBootTest
class SpringbootXyuProjectApplicationTests {
@Autowired
public AmqpAdmin amqpAdmin;
@Test
void contextLoads() {
}
@Test
public void amqpAdmin(){
amqpAdmin.declareExchange(new FanoutExchange("fanout_exchange"));
// 定义一个交换机
amqpAdmin.declareQueue(new Queue("fanout_queue_email"));
amqpAdmin.declareQueue(new Queue("fanout_queue_sms"));
// 绑定
amqpAdmin.declareBinding(new Binding(
"fanout_queue_email", // 绑定的目标队列名称
Binding.DestinationType.QUEUE, // 目标类型是队列
"fanout_exchange", // 交换机的名称
"", // 对于 Fanout 交换机,路由键为空字符串
null // 附加参数,通常用于更高级的绑定配置,当前没有使用
));
amqpAdmin.declareBinding(new Binding(
"fanout_queue_sms", // 绑定的目标队列名称
Binding.DestinationType.QUEUE, // 目标类型是队列
"fanout_exchange", // 交换机的名称
"", // 对于 Fanout 交换机,路由键为空字符串
null // 附加参数,通常用于更高级的绑定配置,当前没有使用
));
}
}
- 消息发送: 使用 RabbitTemplate
来发送消息。通过 RabbitTemplate
的 convertAndSend
方法发送消息到指定的交换机、路由键等
- 创建实体类,发送信息
arduino
/*
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.xyu.po;
/**
* @author <a href="mailto:[email protected]">theonefx</a>
*/
public class User {
private String name;
private Integer age;
@Override
public String toString() {
return "User{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
2.序列化(将实体类实现JDK自带的Serializable序列化接口--对结果进行加密. 定制其他类型的消息转换器)
jackson转换器
kotlin
package com.xyu.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;
@Configuration
public class RabbitMQConfig {
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
将 Java 对象转换为 JSON 字符串。这个过程通常用于将 Java 对象存储为 JSON 格式(比如用于 API 返回数据、文件保存等)
3.传入数据
java
@Test
public void Publisher(){
User user = new User();
user.setAge(18);
user.setName("天天");
rabbitTemplate.convertAndSend("fanout_exchange","",user);
}
效果:
- 消息监听: 使用 @RabbitListener
注解来标记消息接收方法,Spring Boot 会自动监听队列中的消息,并调用相应的方法处理消息。
ini
package com.xyu.Service;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
@Service
public class RabbitMqListenerService {
@RabbitListener(queues = "fanout_queue_email")
public void psubConsumerEmail(Message message) {
byte[] body = message.getBody();
String s = new String(body);
System.out.println("邮件业务接收到消息: "+s);
}
@RabbitListener(queues = "fanout_queue_sms")
public void psubConsumerSms(Message message) {
byte[] body = message.getBody();
String s = new String(body);
System.out.println("短信业务接收到消息: " + s);
}
}
基于配置类的方式(创建两个不同的交换机)
配置交换机
typescript
package com.xyu.Config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
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;
@Configuration
@EnableRabbit
//@EnableRabbit注解在Spring Boot应用中用于启用基于注解的RabbitMQ消息处理功能。
public class RabbitMQConfig {
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange("exchange_my");
}
// 定义不同名称的消息队列
@Bean
public Queue smsQueue() {
return new Queue("fanout_queue_tem", true); // 队列持久化
}
@Bean
public Queue emailQueue() {
return new Queue("fanout_queue_num", true); // 队列持久化
}
// 将消息队列与交换器绑定
@Bean
public Binding smsBinding() {
return BindingBuilder.bind(smsQueue()).to(fanoutExchange());
}
@Bean
public Binding emailBinding() {
return BindingBuilder.bind(emailQueue()).to(fanoutExchange());
}
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
接受信息
less
@RabbitListener(bindings =@QueueBinding(value =
@Queue("fanout_queue_tem"), exchange =
@Exchange(value = "exchange_my"
,type = "fanout")))
public void psubConsumerEmailAno(User user) {
System.out.println("1邮件业务接收到消息: "+user);
}
@RabbitListener(bindings =@QueueBinding(value =
@Queue("fanout_queue_num"),exchange =
@Exchange(value = "exchange_my"
,type = "fanout")))
public void psubConsumerSmsAno(User user) {
System.out.println("1短信业务接收到消息: "+user);
}
发送信息
sql
@Test
public void Publisher(){
User user = new User();
user.setAge(18);
user.setName("天天1");
rabbitTemplate.convertAndSend("fanout_exchange","",user);
rabbitTemplate.convertAndSend("exchange_my","",user);
}
效果展示
Routing(路由模式)
在Routing工作模式中,必须先配置一个direct类 型的交换器,并指定不同的路由键值(Routing key)将对应的消息从交换器路由到不同的消息 队列进行存储,由消费者进行各自消费。
FanoutExchange
是一种专门用于广播消息的交换机类型,它不需要绑定type="direct"
,因为FanoutExchange
本身就是一种无条件广播的交换机类型。- 使用
direct
类型的交换机,那应该使用DirectExchange
typescript
//路由
@Bean
public DirectExchange directExchange(){
return new DirectExchange("routing_exchange");
}
@Bean
public Queue routeQueue(){
return new Queue("routing_queue_all",true);
}
@Bean
public Binding routeBinding(){return BindingBuilder.bind(routeQueue()).to(directExchange()).withQueueName();}
}
typescript
存数据
@Test
public void routingPublisher() {
rabbitTemplate.convertAndSend("routing_exchange"
,
"error_routing_key"
,
"routing send error message");
}
less
@RabbitListener(bindings =@QueueBinding(value =
@Queue("fanout_queue_num"),exchange =
@Exchange(value = "exchange_my"
,type = "fanout")))
public void psubConsumerSmsAno(User user) {
System.out.println("1短信业务接收到消息: "+user);
}
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(name = "routing_queue_all"),
exchange = @Exchange(value = "routing_exchange", type = "direct"),
key = "error_routing_key")
)
public void routingConsumerError(String message) {
System.out.println("接收到error级别日志消息: " + message);
}
}
效果展示
Topics(通配符模式)
定义交换机和队列
typescript
@Bean
public TopicExchange topicExchange(){
return new TopicExchange("topic_exchange");
}
@Bean
public Queue topic_queue_email(){
return new Queue("topic_queue_email",true);
}
@Bean
public BindingBuilder.TopicExchangeRoutingKeyConfigurer topicBinding(){return BindingBuilder.bind(topic_queue_email()).to(topicExchange());}
发数据
typescript
@Test
public void topicPublisher() {
rabbitTemplate.convertAndSend("topic_exchange"
,
"info.email"
,
"topics send email message");
rabbitTemplate.convertAndSend("topic_exchange"
,
"info.sms"
,
"topics send sms message");
rabbitTemplate.convertAndSend("topic_exchange"
,
"info.email.sms"
,
"topics send email and sms message");}
}
取数据
less
@RabbitListener(bindings =@QueueBinding(value =
@Queue("topic_queue_email"),exchange =
@Exchange(value = "topic_exchange"
,type = "topic"),
key = "info.#.sms.#"))
public void topicConsumerSms(String message) {
System.out.println("接收到短信订阅需求处理消息: "+message);
}
}
效果 :