订阅模式-----Fanout(广播)
在在工作模式中:每个任务只被传递给一个工作人员。
在这一部分,我们将做一些完全不同的事情 - 我们将会传递一个信息给多个消费者。 这种模式被称为**“发布/订阅”**。
生产者
与之前的工作模型相比区别就是绑定了一个交换机,其他的参数(Queue、RoutingKey)都为默认值(“”)
RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE
:交换机名称(随意)
RabbitMqConstant.ROUTING_DEFAULT
:默认名称为(“”)
@ApiModel(value = "AmqpSendController",description = "整合amqp进行消息推送")
@RestController
@RequestMapping("/amqpSend")
public class AmqpSendController {
@Autowired
private AmqpTemplate amqpTemplate;
@Autowired
private RabbitTemplate rabbitTemplate;
@PostMapping("/subscription/{message}")
public void subscriptionSend(@PathVariable(value = "message") String message){
System.out.println("subscription发送消息:"+message);
amqpTemplate.convertAndSend(RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE,RabbitMqConstant.ROUTING_DEFAULT,message);
}
}
生产者
@RabbitListener(queues = RabbitMqConstant.QUEUE_WORK_QUEUE,ackMode = "MANUAL")
// 等于 下面的样式 绑定默认的交换机 ,交换机的类型为默认的直连类型
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = RabbitMqConstant.QUEUE_WORK_QUEUE),
exchange = @Exchange(value = RabbitMqConstant.EXCHANGE_DEFAULT,
type = ExchangeTypes.DIRECT)))
与之前的工作模式相比绑定了一个交换机
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_ONE),
exchange = @Exchange(value = RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE,
type = ExchangeTypes.FANOUT),
key = RabbitMqConstant.ROUTING_DEFAULT),
ackMode = "MANUAL")
-
bindings
: 定义了与消息队列绑定相关的设置。value
: 表示队列的相关设置。value = @Queue(value = RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_ONE)
: 声明一个队列,其中RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_ONE
是队列的名称。
exchange
: 表示交换机的相关设置。value = @Exchange(value = RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE,type = ExchangeTypes.FANOUT)
: 声明一个交换机,value
:表示RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE
是交换机的名称。type
: 交换机类型。交换机常用类型有direct
(直连,默认类型)、topic(主题)、fanout(订阅广播模式)
key
: 表示绑定键,用于指定将消息路由到指定队列的规则。RabbitMqConstant.ROUTING_DEFAULT
: 绑定键,用于将消息路由到队列的规则。
两个消费者的交换机
Exchange
是一样的,唯一不同的是队列Queue
。消费者One的队列名称:
RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_ONE
消费者Two的队列名称:
RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_TWO
@Component
public class RabbitMQListener {
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_ONE),
exchange = @Exchange(value = RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE,
type = ExchangeTypes.FANOUT),
key = RabbitMqConstant.ROUTING_DEFAULT),
ackMode = "MANUAL")
public void subscriptionMessageReceiveOne(Message message, Channel channel) {
try {
String messageBody = new String(message.getBody());
//手动确认消息
if (messageBody.length() < 10) {
System.out.println("One SUBSCRIPTION ------------ 消息接收:" + messageBody);
//第一个参数是消息的标记,第二个参数是是否批量处理
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} else {
System.out.println(messageBody + ":消息接收失败!");
new RuntimeException("消息长度大于10");
//第一个参数是消息的标记,第二个参数是是否批量处理,第三个参数,是否重新入队,true为重新入队,false为丢弃该消息
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = RabbitMqConstant.QUEUE_SUBSCRIPTION_ROUTING_TWO),
exchange = @Exchange(value = RabbitMqConstant.EXCHANGE_SUBSCRIPTION_CHANGE,
type = ExchangeTypes.FANOUT),
key = RabbitMqConstant.ROUTING_DEFAULT ),
ackMode = "MANUAL")
public void subscriptionMessageReceiveTwo(Message message, Channel channel) {
try {
String messageBody = new String(message.getBody());
//手动确认消息
if (messageBody.length() < 10) {
System.out.println("Two SUBSCRIPTION ------------ 消息接收:" + messageBody);
//第一个参数是消息的标记,第二个参数是是否批量处理
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} else {
System.out.println(messageBody + ":消息接收失败!");
new RuntimeException("消息长度大于10");
//第一个参数是消息的标记,第二个参数是是否批量处理,第三个参数,是否重新入队,true为重新入队,false为丢弃该消息
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
结果:发送的一个消息被所有订阅的队列消费。
添加新的消费者进入队列:
方法1:手动添加队列信息,并绑定对应的交换机。(推荐,之前队列的消息不会丢失)
**方法2:**删除之前的交换机和队列,可能会有消息丢失。