一.RabbitMQ的订阅/分发模式
FanoutExchange采用广播的方式将消息发送给所绑定的队列,队列将消息推送给订阅了消息的消费者。
二.业务场景模拟
假如一个业务(生产者)所产生的消息,需要供3个服务来使用。
三.生产者实现
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.进行相关配置
3.创建相关队列与交换机并进行绑定
package org.example.rabbitmqfanout;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FanoutConsumerConfig {
//定义交换机
@Bean
FanoutExchange fanoutExchange(){
//三个参数分别为 交换机名 是否持久化 是否自动删除
return new FanoutExchange("fanoutExchange",true,false);
}
//定义队列
@Bean
//两个参数分别为 队列名 是否持久化
Queue emailQueue(){
return new Queue("emailQueue",true);
}
@Bean
Queue msgQueue(){
return new Queue("msgQueue",true);
}
@Bean
Queue orderQueue(){
return new Queue("orderQueue",true);
}
//绑定交换机与队列
@Bean
Binding emailBinding(){
return BindingBuilder.bind(emailQueue()).to(fanoutExchange());
}
@Bean
Binding msgBinding(){
return BindingBuilder.bind(msgQueue()).to(fanoutExchange());
}
@Bean
Binding orderBinding(){
return BindingBuilder.bind(orderQueue()).to(fanoutExchange());
}
}
这里也可以在RabbitMQ的web页面中进行创建。
4.定义消息的生产者
package org.example.rabbitmqfanout.service;
import org.example.rabbitmqfanout.domain.Game;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
public class FanoutService {
@Autowired
public RabbitTemplate rabbitTemplate;
public void doProduce(Game game){
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
String time = simpleDateFormat.format(date);
String msg = "感谢您在" + time + "所购买的" + game.getName() + "共花费" + game.getPrice() + "元";
rabbitTemplate.convertAndSend("fanoutExchange", "", msg);
}
}
5.进行测试
package org.example.rabbitmqfanout;
import org.example.rabbitmqfanout.domain.Game;
import org.example.rabbitmqfanout.service.FanoutService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Component;
@Component
@SpringBootTest
public class Test {
@Autowired
FanoutService service;
@org.junit.jupiter.api.Test
public void test1(){
service.doProduce(new Game("黑神话",198.0,"zzz"));
}
}
可以在RabbitMQ的web界面中看到各队列的情况,所有队列都接收到了消息。
四.消费者实现
1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.进行相关配置
3.定义消息的消费者
package org.example.rabbitmqfanoutconsumer.service;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
//所监听的队列
@RabbitListener(queues = {"emailQueue"})
@Component
public class EmailConsumer {
//处理消息的行为
@RabbitHandler
public void emailConsume(String msg){
System.out.println(msg);
}
}
package org.example.rabbitmqfanoutconsumer.service;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
//所监听的队列
@RabbitListener(queues = {"msgQueue"})
@Component
public class MsgConsumer {
//处理消息的行为
@RabbitHandler
public void msgConsume(String msg){
System.out.println(msg);
}
}
package org.example.rabbitmqfanoutconsumer.service;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
//所监听的队列
@RabbitListener(queues = {"orderQueue"})
@Component
public class OrderConsumer {
//处理消息的行为
@RabbitHandler
public void orderConsume(String msg){
System.out.println(msg);
}
}
4.启动消费者服务
可以看到消息被消费掉了。
五.总结
1.Fanout模式的机制:广播给所有订阅了的队列。
2.通过配置类可以在代码中声明交换机与队列,同时将其进行绑定。
3.消费者通过@RabbitListener定义所接收的队列,通过@RabbitHandler定义消费消息的方法。