一、添加rabbitmq依赖
Springboot为rabbitmq提供了starter,可以非常方便的引入依赖。
<dependencies>
<!--rabbitmq模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
二、基本流程
rabbitmq的一个完整的信息收发流程大概如下图这样。
消息在到达队列之前已经通过了binding的筛选,所以,如果在使用过程中发现消费者接收到了不正确的数据,第一步应该是检查绑定是否正确。
三、各个模式的交换机实例
1、Fanout
配置类,创建队列与交换机,并将它们绑定
@Configuration
public class RabbitFanoutConfig {
public static final String FANOUT_NAME = "tianqicode-fanout";
// 提供两个队列的bean
@Bean
Queue queueOne() {
return new Queue("fanout-queue-one");
}
@Bean
Queue queueTwo() {
return new Queue("fanout-queue-two");
}
// 提供fanout交换机的bean
@Bean
FanoutExchange fanoutExchange() {
// 第一个参数为交换机的名称,第二个参数为是否持久化(重启服务后仍存在), 第三个参数为规定时间未使用自动删除
return new FanoutExchange(FANOUT_NAME, false, false);
}
// 将队列1绑定交换机
@Bean
Binding bindingOne() {
return BindingBuilder.bind(queueOne()).to(fanoutExchange());
}
// 将队列2绑定交换机
@Bean
Binding bindingTwo() {
return BindingBuilder.bind(queueTwo()).to(fanoutExchange());
}
}
消费者类,监听队列
@Component
public class FanoutReceiver {
// 添加消费者1,监听fanout-queue-one
@RabbitListener(queues = "fanout-queue-one")
public void handler1(String msg) {
System.out.println("fanout-handler1>>>>>"+msg);
}
// 添加消费者2,监听fanout-queue-two
@RabbitListener(queues = "fanout-queue-two")
public void handler2(String msg) {
System.out.println("fanout-handler2>>>>>"+msg);
}
}
在测试类中写一个生产者
// fanout模式发送消息,发送给所有绑定此交换机的队列
@Test
public void testFanout() {
// 第一个参数为交换机名称,第二个参数为routingKey,第三个参数为发送的消息
rabbitTemplate.convertAndSend(RabbitFanoutConfig.FANOUT_NAME, null, "hello fanout");
}
2、Direct
配置类
@Configuration
public class RabbitDirectConfig {
public static final String DIRECT_NAME = "tianqicode-direct";
// 创建队列
@Bean
Queue directQueueOne() {
return new Queue("direct-queue-one");
}
@Bean
Queue directQueueTwo() {
return new Queue("direct-queue-two");
}
// 创建交换机
@Bean
DirectExchange directExchange() {
return new DirectExchange(DIRECT_NAME, false, false);
}
// 绑定交换机并规定routingKey
@Bean
Binding directBindingOne() {
return BindingBuilder.bind(directQueueOne()).to(directExchange()).with("direct1");
}
@Bean
Binding directBindingTwo() {
return BindingBuilder.bind(directQueueTwo()).to(directExchange()).with("direct2");
}
}
消费者
@Component
public class DirectReceiver {
// 监听队列
@RabbitListener(queues = "direct-queue-one")
public void directHandler1(String msg) {
System.out.println("directHandler1>>>>>" + msg);
}
@RabbitListener(queues = "direct-queue-two")
public void directHandler2(String msg) {
System.out.println("directHandler2>>>>>" + msg);
}
}
生产者
// direct模式发送消息,然后根据指定的routingKey发送到队列
@Test
public void testDirect() {
// 第一个参数为交换机名称,第二个参数为routingKey,第三个参数为发送的消息
rabbitTemplate.convertAndSend(RabbitDirectConfig.DIRECT_NAME,"direct1","direct 1111");
rabbitTemplate.convertAndSend(RabbitDirectConfig.DIRECT_NAME,"direct2","direct 2222");
}
3、Topic
配置类
@Configuration
public class RabbitTopicConfig {
public static final String TOPIC_NAME = "tianqicode-topic";
// 创建队列
@Bean
Queue xiaomi() {
return new Queue("xiaomi");
}
@Bean
Queue huawei() {
return new Queue("huawei");
}
@Bean
Queue phone() {
return new Queue("phone");
}
// 创建交换机
@Bean
TopicExchange topicExchange() {
return new TopicExchange(TOPIC_NAME, false, false);
}
// 通过routingKey将队列绑定交换机
@Bean
Binding xiaomiBinding() {
// xiaomi.# 代表订阅以xiaomi为前缀的所有消息
// 若不慎将队列绑定为错误的主题,可以到管理页面删除
return BindingBuilder.bind(xiaomi()).to(topicExchange()).with("xiaomi.#");
}
@Bean
Binding huaweiBinding() {
return BindingBuilder.bind(huawei()).to(topicExchange()).with("huawei.#");
}
@Bean
Binding phoneBinding() {
return BindingBuilder.bind(phone()).to(topicExchange()).with("#.phone.#");
}
}
消费者
@Component
public class TopicReceiver {
// 创建消费者
@RabbitListener(queues = "xiaomi")
public void xiaomiHandler(String msg) {
System.out.println("xiaomiHandler>>>>>" + msg);
}
@RabbitListener(queues = "huawei")
public void huaweiHandler(String msg) {
System.out.println("huaweiHandler>>>>>" + msg);
}
@RabbitListener(queues = "phone")
public void phoneHandler(String msg) {
System.out.println("phoneHandler>>>>>>" + msg);
}
}
生产者
// topic模式发送消息,在根据绑定的主题发送到队列
@Test
public void testTopic() {
rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPIC_NAME, "xiaomi.phone.news", "小米将发布新机型信息");
// rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPIC_NAME, "xiaomi.weather", "今日多云");
rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPIC_NAME, "huawei.phone.news", "华为鸿蒙系统开源");
// rabbitTemplate.convertAndSend(RabbitTopicConfig.TOPIC_NAME, "huawei.weather", "今日多云");
}
四、测试一下
1、运行testFanout
控制台打印
所有的队列都收到了消息
2、运行testDirect
队列根据routingKey接收到了消息
3、运行testTopic
主题订阅方式,消息接收更加灵活