Publish/Subscribe 发布/订阅模式,官方定义是每次把消息发送给多个消费者(Sending messages to many consumers at once)。
它的结构式
详细介绍请参照:RabbitMQ Exchange 中的订阅模式(Fanout Exchange)
一、编写代码
1、编写常量类RabbitPublishSubscribeConstant
package com.lvgang.springbootrabbitmq.publishsubscribe;
/**
* @author lvgang
*/
public class RabbitPublishSubscribeConstant {
public static final String QUEUQ_A = "Queue_PublishSubscribe_A";
public static final String QUEUQ_B = "Queue_PublishSubscribe_B";
public static final String QUEUQ_C = "Queue_PublishSubscribe_C";
public static final String EXCHANGE = "Exchange_PublishSubscribe";
}
2、编写配置类RabbitPublishSubscribeConfig
package com.lvgang.springbootrabbitmq.publishsubscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* @author lvgang
*/
@Configuration
public class RabbitPublishSubscribeConfig {
private static Logger logger = LoggerFactory.getLogger(RabbitPublishSubscribeConfig.class);
/**
* Queue 可以有4个参数
* 1.队列名
* 2.durable 持久化消息队列 ,rabbitmq重启的时候不需要创建新的队列 默认true
* 3.auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
* 4.exclusive 表示该消息队列是否只在当前connection生效,默认是false
*/
@Bean
public Queue createPublishSubscribeQueueA() {
logger.info("创建PublishSubscribeQueueA成功");
return new Queue(RabbitPublishSubscribeConstant.QUEUQ_A,true);
}
@Bean
public Queue createPublishSubscribeQueueB() {
logger.info("创建PublishSubscribeQueueB成功");
return new Queue(RabbitPublishSubscribeConstant.QUEUQ_B,true);
}
@Bean
public Queue createPublishSubscribeQueueC() {
logger.info("创建PublishSubscribeQueueC成功");
return new Queue(RabbitPublishSubscribeConstant.QUEUQ_C,true);
}
@Bean
public FanoutExchange publishSubscribeExchange() {
//配置广播路由器
logger.info("创建PublishSubscribeExchange成功");
return new FanoutExchange(RabbitPublishSubscribeConstant.EXCHANGE);
}
@Bean
public Binding bingQueueAToPublishSubscribeExchange() {
logger.info("绑定PublishSubscribeQueueA到PublishSubscribeExchange成功");
return BindingBuilder.bind(createPublishSubscribeQueueA()).to(publishSubscribeExchange());
}
@Bean
public Binding bingQueueBToPublishSubscribeExchange() {
logger.info("绑定PublishSubscribeQueueB到PublishSubscribeExchange成功");
return BindingBuilder.bind(createPublishSubscribeQueueB()).to(publishSubscribeExchange());
}
@Bean
public Binding bingQueueCToPublishSubscribeExchange() {
logger.info("绑定PublishSubscribeQueueC到PublishSubscribeExchange成功");
return BindingBuilder.bind(createPublishSubscribeQueueC()).to(publishSubscribeExchange());
}
}
3、编写消息生产者PublishSubscribeSender
package com.lvgang.springbootrabbitmq.publishsubscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.UUID;
/**
* @author lvgang
*/
@Component
public class PublishSubscribeSender {
private static Logger logger = LoggerFactory.getLogger(PublishSubscribeSender.class);
@Autowired
private RabbitTemplate rabbitTemplate;
public void send(int i) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
String content = "ExchangeFanout="+ i+"," + new Date() + ", content= " + UUID.randomUUID().toString();
//消息发送,使用void convertAndSend(String exchange, String routingKey, Object message) throws AmqpException;
//但不指定routingKey。因为FanoutExchange类型的交换机,routingKey不起作用,它向所有的队列发送广播,只要队列绑定到该交换机即接受消息。
this.rabbitTemplate.convertAndSend(RabbitPublishSubscribeConstant.EXCHANGE,"",content,correlationData);
logger.info("Send ok,"+new Date()+","+content);
}
}
4、编写消息接收者APublishSubscribeReceiverA
package com.lvgang.springbootrabbitmq.publishsubscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author lvgang
*/
@Component
@RabbitListener(queues = RabbitPublishSubscribeConstant.QUEUQ_A)
public class PublishSubscribeReceiverA {
private static Logger logger = LoggerFactory.getLogger(PublishSubscribeReceiverA.class);
@RabbitHandler
public void process(String message) {
logger.info("ReceiverA : " + message +","+ new Date());
}
}
5、编写消息接收者B PublishSubscribeReceiverB
package com.lvgang.springbootrabbitmq.publishsubscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author lvgang
*/
@Component
@RabbitListener(queues = RabbitPublishSubscribeConstant.QUEUQ_B)
public class PublishSubscribeReceiverB {
private static Logger logger = LoggerFactory.getLogger(PublishSubscribeReceiverB.class);
@RabbitHandler
public void process(String message) {
logger.info("ReceiverB : " + message +","+ new Date());
}
}
6、编写消息接收者C PublishSubscribeReceiverC
package com.lvgang.springbootrabbitmq.publishsubscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author lvgang
*/
@Component
@RabbitListener(queues = RabbitPublishSubscribeConstant.QUEUQ_C)
public class PublishSubscribeReceiverC {
private static Logger logger = LoggerFactory.getLogger(PublishSubscribeReceiverC.class);
@RabbitHandler
public void process(String message) {
logger.info("ReceiverC : " + message +","+ new Date());
}
}
二、测试结果
1、编写测试类PublishSubscribeTests
package com.lvgang.springbootrabbitmq.publishsubscribe;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author lvgang
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class PublishSubscribeTests {
private static Logger logger = LoggerFactory.getLogger(RabbitPublishSubscribeConfig.class);
@Autowired
private PublishSubscribeSender publishSubscribeSender;
@Test
public void hello() throws Exception {
int i=1;
while (true) {
try {
if(i<=1) {
publishSubscribeSender.send(i);
}
i++;
Thread.sleep(1000);
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
}
}
}
2、执行测试类,并查看结果
通过执行测类,查看到了消息消费的情况,生产者共计生产了1个消息,这1个消息分别被消费者A\B\C都消费过了