通过学习Dierect Exchange以及Topic Exchange,我们已经知道RabbitMQ无非就是创建相应的交换机、队列、以及将队列与交换机进行绑定,上面两种方式的交换机都需要指定相应的route key才能完成消息的分发。本章讲解的Fanout Exchange交换机其实是一种广播式的消息通信方式,只要某个队列与Fanout Exchange交换机进行了绑定,那么一条消息发送到交换机,这条消息就会被分发到所有进行绑定的消息接收者身上。无需指定route key,即使指定了route key路由键也会被忽略掉。可以借助下图来进行理解:
从上图总结几点:
【a】队列一、队列二都与Fanout Exchange交换机进行了绑定,所以当消息发送到交换机的时候,这些消息都会被分发到各个队列对应的消息接收者一和消息接收二上;同理,队列三没有绑定交换机,所以消息不会被分发到队列三上面。
【b】广播式消息消费方式,没有route key之说,不需要指定route key,即使指定了也会被忽略掉。所以我们一般传入空字符串“”就行。
【c】广播式消息分发,有助于我们对同一种消息进行分别处理。举个例子,加入当有会员注册的时候,我们通常需要赠送积分和保存会员信息等操作,这时候就可以构建一个保存会员队列与赠送积分队列,分别进行相应的逻辑处理。
springboot_rabbitmq_fanout_exchange:端口1111
项目结构:
同样引入spring-boot-starter-amqp的依赖,具体pom.xml如下:
4.0.0
com.springboot.wsh
springboot_rabbitmq_fanout_exchange
0.0.1-SNAPSHOT
jar
springboot_rabbitmq_fanout_exchange
RabbitMQ 广播模式
org.springframework.boot
spring-boot-starter-parent
1.5.2.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-amqp
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
server:
port: 1111
spring:
application:
name: rabbit-fanout-exchange
rabbitmq:
host: localhost
username: guest
password: guest
port: 5672
virtual-host: /
publisher-confirms: true
主要存放一些交换机名称、队列名称等,方便后期维护。
/**
* @Title: Constants
* @ProjectName springboot_rabbitmq_fanout_exchange
* @Description: 常量类
* @Author WeiShiHuai
* @Date 2018/9/23 21:21
*/
public class Constants {
/**
* 交换机名称
*/
public static final String FANOUT_EXCHANGE_NAME = "fanout.exchange.name";
/**
* 测试队列名称1
*/
public static final String TEST_QUEUE1_NAME = "test.queue1.name";
/**
* 测试队列名称1
*/
public static final String TEST_QUEUE2_NAME = "test.queue2.name";
}
主要创建Fanout Exchange交换机实例、队列实例以及将队列绑定到交换机上。
/**
* @Title: TestExchangeConfiguration
* @ProjectName springboot_rabbitmq_fanout_exchange
* @Description: RabbitMQ Fanout Exchange配置类
* @Author WeiShiHuai
* @Date 2018/9/23 21:34
*
* 说明:
* 1. fanout路由又称为广播路由,会将收到的消息广播到消息对列上。当使用fanout交换器时,它会将消息广播到与该交换器绑定的所有队列上,有利于对单条消息做不同的反应。
* 2. fanout路由无需指定route key,即使指定了也会被忽略,只要队列与交换机绑定,那么发送到交换机上的消息就会被分发到消息接收者上。
*/
@Configuration
public class TestExchangeConfiguration {
private static Logger logger = LoggerFactory.getLogger(TestExchangeConfiguration.class);
/**
* 创建广播形式的交换机
*
* @return 交换机实例
*/
@Bean
public FanoutExchange fanoutExchange() {
logger.info("【【【交换机实例创建成功】】】");
return new FanoutExchange(Constants.FANOUT_EXCHANGE_NAME);
}
/**
* 测试队列一
*
* @return 队列实例
*/
@Bean
public Queue queue1() {
logger.info("【【【测试队列一实例创建成功】】】");
return new Queue(Constants.TEST_QUEUE1_NAME);
}
/**
* 测试队列二
*
* @return 队列实例
*/
@Bean
public Queue queue2() {
logger.info("【【【测试队列二实例创建成功】】】");
return new Queue(Constants.TEST_QUEUE2_NAME);
}
/**
* 绑定队列一到交换机
*
* @return 绑定对象
*/
@Bean
public Binding bingQueue1ToExchange() {
logger.info("【【【绑定队列一到交换机成功】】】");
return BindingBuilder.bind(queue1()).to(fanoutExchange());
}
/**
* 绑定队列二到交换机
*
* @return 绑定对象
*/
@Bean
public Binding bingQueue2ToExchange() {
logger.info("【【【绑定队列二到交换机成功】】】");
return BindingBuilder.bind(queue2()).to(fanoutExchange());
}
}
注入RabbitTemplate,进行消息的分发
/**
* @Title: TestSender
* @ProjectName springboot_rabbitmq_fanout_exchange
* @Description: 消息发送者
* @Author WeiShiHuai
* @Date 2018/9/23 21:45
*/
@Component
public class TestSender {
private static Logger logger = LoggerFactory.getLogger(TestFanoutExchangeController.class);
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送消息
*
* @param message 消息内容
* 说明: routingKey可以指定也可以不指定,这里我们给一个空字符串""
*/
public void sendMessage(Object message) {
logger.info("【消息发送者】发送消息到fanout交换机,消息内容为: {}", message);
rabbitTemplate.convertAndSend(Constants.FANOUT_EXCHANGE_NAME, "", message);
}
}
分别创建两个消息接收者,使用@RabbitListener指定队列名称以及@RabbitHandler处理消息接收
/**
* @Title: TestReceiver
* @ProjectName springboot_rabbitmq_fanout_exchange
* @Description: 消息接收者
* @Author WeiShiHuai
* @Date 2018/9/23 21:55
*/
@Component
@RabbitListener(queues = "test.queue1.name")
public class TestReceiver {
private static Logger logger = LoggerFactory.getLogger(TestReceiver.class);
@RabbitHandler
public void receiveMessage(Object message) {
logger.info("消息接收者接收到来自【队列一】的消息,消息内容: {}", message);
}
}
/**
* @Title: TestReceiver2
* @ProjectName springboot_rabbitmq_fanout_exchange
* @Description: 消息接收者2
* @Author WeiShiHuai
* @Date 2018/9/23 21:55
*/
@Component
@RabbitListener(queues = "test.queue2.name")
public class TestReceiver2 {
private static Logger logger = LoggerFactory.getLogger(TestReceiver2.class);
@RabbitHandler
public void receiveMessage(Object message) {
logger.info("消息接收者接收到来自【队列二】的消息,消息内容: {}", message);
}
}
注入消息发送者,并且模拟发送了一串uuid,
/**
* @Title: TestFanoutExchangeConstroller
* @ProjectName springboot_rabbitmq_fanout_exchange
* @Description: 测试Controller
* @Author WeiShiHuai
* @Date 2018/9/23 21:25
*/
@RestController
public class TestFanoutExchangeController {
@Autowired
private TestSender testSender;
@GetMapping("/testFanoutExchange")
public String testFanoutExchange() {
//测试消息发送
String message = UUID.randomUUID().toString();
testSender.sendMessage(message);
return "success";
}
}
启动项目,如下图
可以看到,各个需要的实例都创建成功,访问http://localhost:1111/testFanoutExchange,
可以看到,消息接收者成功接收到了消息发送者发送的消息。
至此,Fanout Exchange广播式交换机都已经实现完成,总体来说比Direct Exchange和Topic Exchange简单些,配置相对比较简单。总之,记住Fanout Exchange无需指定route key,只要和交换机进行绑定,那么消息就会被成功分发到消息接收者身上。本文是作者在学习Fanout Exchange的一些总结和使用经验,仅供大家参考,一起学习,共同进步!