开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
上篇回顾
上篇给大家介绍了AMQP高级消息协议、RabbitMQ的优势、RabbitMQ组件功能(Broker、Virtual Host、Exchange、Queue、Binding)等基本概论。这些内容对于接下来的代码部分的学习起到了很好的铺垫作用。
我们知道交换机有Direct、Topic、Headers和Fanout四种消息分发类型。为了便于大家理解,我贴出了四种方式的示意图如下:
Direct模式
Direct是RabbitMQ默认的交换机模式,也是简单的模式,根据key全字匹配去寻找队列
Topic模式
Topic是RabbitMQ中使用最多的交换机模式(见图12-4),RoutingKey必须是一串字符,用符号“.”隔开,比如user.msg或者user.order.msg等
Headers模式
Headers也是根据规则匹配的,相较于Direct和Topic固定地使用RoutingKey与BindingKey的匹配规则来路由消息,Headers是根据发送的消息内容中的headers属性进行匹配的
Fanout模式
Fanout是消息广播模式,交换机不处理RoutingKey,发送到交换机的消息都会分发到所有绑定的队列上。Fanout模式不需要RoutingKey,只需要提前将交换机与队列进行绑定即可。
准备工作
step1
安装一下RabbitMQ服务,我是Docker容器中部署的,操作命令我给贴出来,小伙伴们照着步骤copy执行就可以啦!
1、docker search rabbitmq:management
2、docker pull rabbitmq:management
3、docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management
执行成功后可以通过访问 “http://127.0.0.1:15672” 这个地址,若成功出现如下界面则代表部署成功了,默认登录账号密码都是guest
step2
Spring Boot提供了spring-bootstarter-amqp组件对消息队列进行支持,使用非常简单,仅需要非常少的配置即可实现完整的消息队列服务。利用IDEA新建一个SpringBoot项目,具体步骤我就省略了,然后在pom文件中加入如下引用:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
step3
在项目的application.yml文件中填写RabbitMQ相关配置信息
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
上代码!
简单队列模式
简单队列是RabbitMQ中最简单的工作队列模式,也叫点对点模式,即一个消息的生产者对应一个消费者,它包含一个生产者、一个消费者和一个队列。生产者向队列中发送消息,消费者从队列中获取消息并消费。
1.创建生产者
生产者用来产生消息并进行发送,需要用到RabbitTemplate类。msg类型不限定,这里也可以传入Object对象。
@Slf4j
@Component
public class Producer {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送字符串
*/
public void sendStr(){
String msg ="hello world";
rabbitTemplate.convertAndSend("rabbitmq_queue",msg);
}
/**
* 发送对象
*/
public void sendObj(){
Object msg = ...;
rabbitTemplate.convertAndSend("rabbitmq_queue",msg);
}
}
2.创建消费者
消费者可以消费生产者发送的消息。接下来创建消费者类Consumer,并使用@RabbitListener注解来指定消息的处理方法。
@Slf4j
@Component
public class Consumer {
/**
* @RabbitListener Consumer消费者通过@RabbitListener注解创建侦听器端点,绑定rabbitmq_queue队列
* @param message 待处理的消息
*/
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("rabbitmq_queue"))
public void process(String message){
log.info("消费者消息:{}",message);
}
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("rabbitmq_queue"))
public void process(Object message){
log.info("消费者消息:{}",message);
}
}
3.创建测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest{
@Autowired
Producer producer;
@Test
public void test(){
producer.sendStr();
Thread.sleep(1000)
}
}
工作队列模式
与简单队列模式的代码大致相同,生产者不变,只是有多个消费者而已,此时每条消息只会被消费一次,多个消费者循环处理消息。
1.创建生产者
创建一个生产者用来循环产生100条消息发送到队列。
@Slf4j
@Component
public class Producer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void produce(){
for (int i = 0; i < 100; i++) {
String msg = new Date() + " beiging";
rabbitTemplate.convertAndSend("work_queue",msg);
}
}
}
2.创建消费者
创建2个消费者ConsumerA和ConsumerB
@Slf4j
@Component
public class ConsumerA {
/**
* @RabbitListener Consumer消费者通过@RabbitListener注解创建侦听器端点,绑定rabbitmq_queue队列
* @param message 待处理的消息
*/
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("work_queue"))
public void process(String message) throws InterruptedException {
Thread.sleep(1000);
log.info("ConsumerA消费者消息:{}",message);
}
}
@Slf4j
@Component
public class ConsumerB {
/**
* @RabbitListener Consumer消费者通过@RabbitListener注解创建侦听器端点,绑定rabbitmq_queue队列
* @param message 待处理的消息
*/
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("work_queue"))
public void process(String message) throws InterruptedException {
Thread.sleep(1000);
log.info("ConsumerB消费者消息:{}",message);
}
}
3.创建测试类
@Test
public void workQueueModel() throws InterruptedException {
workProducer.produce();
Thread.sleep(800000);
}
路由模式
之前介绍了Direct路由转发模式是“先匹配,再发送”,即在绑定时设置一个BindingKey,当消息的RoutingKey匹配队列绑定的BindingKey时,才会被交换机发送到绑定的队列中。
1.配置Direct规则
创建Direct规则配置类DirectRabbitConfig,创建对应的Exchange、Queue,并将队列绑定到交换机上。
@Configuration
public class DirectRabbitConfig {
/**
* 队列一
* @return
*/
@Bean
public Queue directQueueQ1(){
return new Queue("direct.Q1");
}
/**
* 队列二
* @return
*/
@Bean
public Queue directQueueQ2(){
return new Queue("direct.Q2");
}
/**
* 队列三
* @return
*/
@Bean
public Queue directQueueQ3(){
return new Queue("direct.Q3");
}
/**
* 定义交换机Direct类型
* @return
*/
@Bean
public DirectExchange myDirectExchange(){
return new DirectExchange("directExchange");
}
/**
* 队列绑定到交换机,再指定一个路由键
* @return
*/
@Bean
public Binding DirectExchangeQ1(){
return BindingBuilder.bind(directQueueQ1()).to(myDirectExchange()).with("direct.Q1");
}
@Bean
public Binding DirectExchangeQ2(){
return BindingBuilder.bind(directQueueQ2()).to(myDirectExchange()).with("direct.Q2");
}
@Bean
public Binding DirectExchangeQ3(){
return BindingBuilder.bind(directQueueQ3()).to(myDirectExchange()).with("direct.Q3");
}
}
2.生产者
创建生产者发送消息,通过convertAndSend()方法发送消息,传入directExchange、routingKey、context三个参数。
- directExchange为交换机名称。
- routingKey为消息的路由键。
- context为消息的内容。
@Slf4j
@Component
public class DirectProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void produce(String routingKey) {
String context = "direct msg weiz";
System.out.println("Direct Sender,routingKey: " + routingKey+",context:"+context);
this.rabbitTemplate.convertAndSend("directExchange",routingKey, context);
}
}
3.消费者
创建3个消费者处理程序,分别监听Q1、Q2、Q3
@Slf4j
@Component
public class DirectConsumer {
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("direct.Q1"))
public void processQ1(String message) {
System.out.println("direct Receiver Q1: " + message);
}
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("direct.Q2"))
public void processQ2(String message) {
System.out.println("direct Receiver Q2: " + message);
}
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue("direct.Q3"))
public void processQ3(String message) {
System.out.println("direct Receiver Q3: " + message);
}
}
4.测试方法
@Test
public void test() throws InterruptedException {
directProducer.produce("direct.Q1");
directProducer.produce("direct.Q3");
Thread.sleep(2000);
}
广播模式
Fanout就是熟悉的广播模式或者订阅模式,每个发送到Fanout类型交换机的消息都会分到所有绑定的队列上。 Fanout模式很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout类型转发消息是最快的。
1. 配置Fanout规则
先创建Fanout规则配置类FanoutRabbitConfig,再创建对应的Exchange、Queue,并将队列绑定到交换机上。
@Configuration
public class FanoutRabbitConfig {
@Bean
public Queue Q1Message(){
return new Queue("fanout.Q1");
}
@Bean
public Queue Q2Message(){
return new Queue("fanout.Q2");
}
@Bean
public Queue Q3Message(){
return new Queue("fanout.Q3");
}
@Bean
FanoutExchange fanoutExchange(){
return new FanoutExchange("fanoutExchange");
}
@Bean
Binding bindingExchangeQ1(Queue Q1Message,FanoutExchange fanoutExchange){
return BindingBuilder.bind(Q1Message).to(fanoutExchange);
}
@Bean
Binding bindingExchangeQ2(Queue Q2Message,FanoutExchange fanoutExchange){
return BindingBuilder.bind(Q2Message).to(fanoutExchange);
}
@Bean
Binding bindingExchangeQ3(Queue Q3Message,FanoutExchange fanoutExchange){
return BindingBuilder.bind(Q3Message).to(fanoutExchange);
}
}
2. 发送者
创建发送者
@Slf4j
@Component
public class FanoutProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void produce() {
String context = "fanout msg weiz";
System.out.println("Fanout Sender : " + context);
this.rabbitTemplate.convertAndSend("fanoutExchange", "", context);
}
}
3. 接收者
创建3个接收者分别监听Q1、Q2、Q3队列。
@Slf4j
@Component
public class FanoutConsumer {
@RabbitHandler
@RabbitListener(queues = "fanout.Q1")
public void processA(String message){
log.info("fanout receiver Q1:{}",message);
}
@RabbitHandler
@RabbitListener(queues = "fanout.Q2")
public void processB(String message){
log.info("fanout receiver Q2:{}",message);
}
@RabbitHandler
@RabbitListener(queues = "fanout.Q3")
public void processC(String message){
log.info("fanout receiver Q3:{}",message);
}
}
4.测试
@Autowired
FanoutProducer fanoutProducer;
@Test
void fanout() throws InterruptedException {
fanoutProducer.produce();
Thread.sleep(10000);
}
发布订阅模式
Topic是RabbitMQ中灵活的一种方式,可以根据路由键绑定不同的队列。Topic类型的Exchange与Direct相比,都可以根据路由键将消息路由到不同的队列。只不过Topic类型的Exchange可以让队列在绑定路由键时使用通配符。有关通配符的规则为:
- #:匹配一个或多个词。
- *:只匹配一个词。
1. 配置Topic规则
先创建Topic配置规则类TopicRabbitConfig,再创建对应的Exchange、Queue,并将队列绑定到交换机上
@Configuration
public class TopicRabbitConfig {
final static String message1 = "topic.color";
final static String message2 = "topic.color.red";
final static String message3 = "topic.msg.feedback";
@Bean
public Queue queueMessage1(){
return new Queue(TopicRabbitConfig.message1);
}
@Bean
public Queue queueMessage2(){
return new Queue(TopicRabbitConfig.message2);
}
@Bean
public Queue queueMessage3(){
return new Queue(TopicRabbitConfig.message3);
}
@Bean
TopicExchange topicExchange(){
return new TopicExchange("topicExchange");
}
/**
* 将队列和交换机绑定
* @param queueMessage1
* @param topicExchange
* @return
*/
@Bean
Binding bindingExchangeMessage1(Queue queueMessage1,TopicExchange topicExchange){
return BindingBuilder.bind(queueMessage1).to(topicExchange).with("topic.color.*");
}
@Bean
Binding bindingExchangeMessage2(Queue queueMessage2,TopicExchange topicExchange){
return BindingBuilder.bind(queueMessage2).to(topicExchange).with("topic.color.red");
}
@Bean
Binding bindingExchangeMessage3(Queue queueMessage3,TopicExchange topicExchange){
return BindingBuilder.bind(queueMessage3).to(topicExchange).with("topic.msg.*");
}
}
2. 生产者
创建生产者,通过routingKey往绑定的队列发送消息
@Slf4j
@Component
public class TopicProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
public void produce(String routingKey) {
String context = "topic msg weiz";
System.out.println("Topic Sender,routingKey : " +routingKey+" context:"+ context);
this.rabbitTemplate.convertAndSend("topicExchange", routingKey, context);
}
}
3. 消费者
创建消费者类,然后使用@RabbitListener监听3个队列
@Slf4j
@Component
public class TopicConsumer {
@RabbitHandler
@RabbitListener(queues = "topic.color")
public void processA(String message){
log.info("topic.color---------> receiver :{}",message);
}
@RabbitHandler
@RabbitListener(queues = "topic.color.red")
public void processB(String message){
log.info("topic.color.red----------> receiver :{}",message);
}
@RabbitHandler
@RabbitListener(queues = "topic.msg.feedback")
public void processC(String message){
log.info("topic.msg.feedback----------> receiver :{}",message);
}
}
4.测试
@Autowired
TopicProducer topicProducer;
@Test
void testTopic() throws InterruptedException {
//topicProducer.produce("topic.color.green");
topicProducer.produce("topic.color.red");
//topicProducer.produce("topic.msg.feedback");
Thread.sleep(1000);
}
好了,以上就是RabbitMQ几种分发模式的样例代码了,小伙伴们学废了没?