rabbitmq企业开发实战2
第二章 rabbitmq 发布订阅模式实战文章目录
场景
1. 异步通知
例如:用户在注册完后一般都会发送消息通知用户注册成功(失败)。如果在一个系统中,用户注册信息有邮箱、手机号,那么在注册完后会向邮箱和手机号都发送注册完成信息。利用MQ实现业务异步处理,如果是用工作队列的话,就会声明一个注册信息队列。注册完成之后生产者会向队列提交一条注册数据,消费者取出数据同时向邮箱以及手机号发送两条消息。但是实际上邮箱和手机号信息发送实际上是不同的业务逻辑,不应该放在一块处理。这个时候就可以利用发布/订阅模式将消息发送到转换机(EXCHANGE),声明两个不同的队列(邮箱、手机),并绑定到交换机。这样生产者只需要发布一次消息,两个队列都会接收到消息发给对应的消费者。
为什么这个场景要用这个模式?一次生产多端消费,简单模式一次生产,单端消费就没了
一、什么是发布/订阅模式(Publish/Subscribe)?
简单解释就是,可以将消息发送给不同类型的消费者。做到发布一次,消费多个。下图取自于官方网站(RabbitMQ)的发布/订阅模式的图例
P:消息的生产者
X:交换机
红色:队列
C1 (发送邮件),C2(发送短信):消息消费者
二、实战操作
1.定义fanout 交换机,定义两个队列,并将两个队列绑定到该交换机上
代码如下(示例):
package net.getbang.rabbitmq.fanout;
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.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FanoutBuildConfig {
/**
* 定义一个fanout 类型的交换机
* @return
*/
@Bean
FanoutExchange testFanoutExchange(){
return new FanoutExchange("fanout-test");
}
/**
* 定义邮件发送队列
*/
@Bean
public Queue queueEmail(){
return new Queue("fanout.email");
}
/**
* 定义短信发送队列
*/
@Bean
public Queue queueSms(){
return new Queue("fanout.sms");
}
/**
* 将队列绑定到交换机上
*/
@Bean
Binding bindingExchangeMessage(@Qualifier("queueEmail")Queue queueMessage, FanoutExchange testFanoutExchange) {
return BindingBuilder.bind(queueMessage).to(testFanoutExchange);
}
@Bean
Binding bindingExchangeMessages(@Qualifier("queueSms")Queue queueMessages, FanoutExchange testFanoutExchange) {
return BindingBuilder.bind(queueMessages).to(testFanoutExchange);
}
}
比简单模式多了定义交换机以及绑定的两个操作。1
2.定义消费生产者
复制简单模式的消息生产者,在原来发送消息的方法中添加交换机的名字属性,添加后点击进去到方法
public void sendFanout(String exchangeName,String queueName, Object message){
rabbitTemplate.setDefaultReceiveQueue(queueName);
rabbitTemplate.convertAndSend(exchangeName,queueName,message);
}
@Override
public void convertAndSend(String exchange, String routingKey, final Object object) throws AmqpException {
convertAndSend(exchange, routingKey, object, (CorrelationData) null);
}
发现这里已经中间不是队列的名称,而是routingKey 了,我们没有,所以暂时先空着,后续说明作用
代码如下(示例):
package net.getbang.rabbitmq.producer;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class FanoutProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendFanout(String exchangeName,Object message){
rabbitTemplate.convertAndSend(exchangeName,"",message);
}
}
消息消费
代码如下(示例):
package net.getbang.rabbitmq.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class FanoutListener {
@RabbitListener(queues = "fanout.email")
public void reviceFanout(Object message){
System.out.println("FanoutListener.reviceFanout 接收的消息:"+message);
System.out.println("发送邮件");
}
@RabbitListener(queues = "fanout.sms")
public void reviceFanout2(Object message){
System.out.println("FanoutListener.reviceFanout2 接收的消息:"+message);
System.out.println("发送短信");
}
}
测试类代码测试发送消息
@Autowired
FanoutProducer fanoutProducer;
/**
* fanout 模式发送消息测试
*/
@Test
public void sendFanoutMessage(){
Map<String,String> messageBody =new HashMap(2);
messageBody .put("会员id","66666");
fanoutProducer.sendFanout("fanout-test",messageBody);
}
结果如下,达到目的
问题:上门发送消息中间空的routingkey 是什么场景下用的呢?
***斜体样式***代码位置:
源码链接: https://code.aliyun.com/411741962/rabbitmq-springboot.git
QQ群交流 671243328
注脚的解释 ↩︎