RabbitMQ主要有六种工作模式。本文结合SpringBoot介绍工作模式的实现。前提概念Producer消息生产者或发送者,用P表示:队列消息从生产端发送到消费者端,必须通过队列转发,用queue_name表示:消费者消费的消费者或接收者,用C表示表示,if多个消费者也可以用C1和C2表示:SpringBoot集成RabbitMQ基础配置,添加maven依赖org.springframework.bootspring-boot-starter-amqp2.2.1.RELEASE添加application.yml配置spring:rabbitmq:host:192.168.3.19端口:5672用户名:admin密码:123456消息生产生产端发送消息和调用RabbitTemplate发送消息,如:@AutowiredprivateRabbitTemplaterabbitTemplate;publicStringsend(){rabbitTemplate.convertAndSend("routingKey","sendmessage");}消费消息使用队列监听注解@RabbitListener消费消息,添加要消费的队列名并发送到队列中消息上来了:@RabbitListener(queuesToDeclare=@Queue("queue_name"))publicvoidconsume(Stringmessage){//接收消息}1.简单(simple)模式最简单的消息发送特性生产者是消费者是一一对应的也称为点对点模式,生产者直接通过队列向消费者发送消息。生产者和消费者在发送和接收消息时,只需要指定队列名即可,无需指定Exchange开关。代码示例制作消息:@GetMapping("/simple-send")publicStringsimpleSend(){rabbitTemplate.convertAndSend("simple","thisisnews");return"ok";}consumptionmessage@RabbitListener(queuesToDeclare=@Queue("simple"))publicvoidconsume(Stringmessage){System.out.println(message);}Output:thisisnews不需要创建开关和绑定队列,只需要匹配消息发送成功的发送者和消费者的队列名即可。2.工作模式在多个消费者之间分发任务。工作模式与简单模式类似,只需要生产端、消费端和队列。不同的是,一个生产者和一个队列对应多个消费者,即一对多的关系。在多个消费者之间分发消息(竞争消费者模式),类似于轮询发送消息,每条消息只发送给一个消费者。代码示例生产消息:@GetMapping("/work-send")publicStringsimpleSend(){rabbitTemplate.convertAndSend("work","thisisnews");return"ok";}消费消息:@RabbitListener(queuesToDeclare=@Queue("work"))publicvoidconsume(Stringmessage){System.out.println("first:"+message);}@RabbitListener(queuesToDeclare=@Queue("work"))publicvoidconsumeSecond(Stringmessage){System.out.println("second:"+message);}创建一个生产者,两个消费者,发送两条消息,两个消费者分别接收消息,输出:first:thisisnewssecond:thisisnews两个消费者,依次消费新闻。类似于nginx负载均衡。3.发布订阅一次向多个消费者发送消息的特性。发布和订阅类似于广播消息。每条消息都可以发送给同时订阅该消息的消费者。上图中的X代表开关。使用的扇形开关(fanout),它将发送的消息发送到所有绑定交换器的队列中。创建队列、交换和绑定的代码示例:@BeanpublicFanoutExchangefanoutExchange(){returnnewFanoutExchange("PUBLISH_SUBSCRIBE_EXCHANGE");}@BeanpublicQueuepsFirstQueue(){returnnewQueue("psFirstQueue");}@BeanpublicQueuepsSecondQueue(){returnnewQueue("psSecondQueue");}@BeanpublicQueuepsThirdQueue(){returnnewQueue("psThirdQueue");}@BeanpublicBindingroutingFirstBinding(){returnBindingBuilder.bind(psFirstQueue()).to(fanoutExchange());}@BeanpublicBindingroutingSecondBinding(){returnBindingBuilder.bind(psSecondQueue()).to(fanoutExchange());}@BeanpublicBindingroutingThirdBinding(){returnBindingBuilder.bind(psThirdQueue()).to(fanoutExchange());}上面定义了一个exchangefanoutExchange。分别绑定三个队列psFirstQueue、psSecondQueue、psThirdQueue。队列绑定交换机不需要routingKey,直接绑定即可。生产端:@GetMapping("/publish-sub-send")publicStringpublishSubSend(){rabbitTemplate.convertAndSend("PUBLISH_SUBSCRIBE_EXCHANGE",null,"publish/subscribehello");return"ok";}无需指定routingKey,set为null。消费者:@RabbitListener(queues="psFirstQueue")publicvoidpubsubQueueFirst(Stringmessage){System.out.println("【first】:"+message);}@RabbitListener(queues="psSecondQueue")publicvoidpubsubQueueSecond(Stringmessage){System.out.println("【second】:"+message);}@RabbitListener(queues="psThirdQueue")publicvoidpubsubQueueThird(Stringmessage){System.out.println("【third】:"+message);}Output:[first]:publish/subscribehello[second]:publish/subscribehello[third]:publish/subscribehello发送消息,所有绑定的队列都能收到消息。4.路由模式根据routingKey特性选择性接收消息。每个队列根据不同的routingKeys绑定到交换机。消息发送到交换机再通过routingKey发送到特定的队列,再传递给消费者进行消费。交换从扇出更改为直接。创建队列、开关和绑定的代码示例:@BeanpublicQueueroutingFirstQueue(){returnnewQueue("routingFirstQueue");}@BeanpublicQueueroutingSecondQueue(){returnnewQueue("routingSecondQueue");}@BeanpublicQueueroutingThirdQueue(){returnnewQueue("routingThirdQueue");}@BeanpublicDirectExchangeroutingExchange(){returnnewDirectExchange("routingExchange");}@BeanpublicBindingroutingFirstBind(){returnBindingBuilder.bind(routingFirstQueue()).to(routingExchange()).with("firstRouting");}@BeanpublicBindingroutingSecondBind(){returnBindingBuilder.bind(routingSecondQueue()).to(routingExchange()).with("secondRouting");}@BeanpublicBindingroutingThirdBind(){returnBindingBuilder.bind(routingThirdQueue()).to(routingExchange()).with("thirdRouting");}创建一个交换机,根据不同的路由规则匹配不同的队列routingExchange,根据不同的routingKey绑定不同的队列:firstRouting的路由键绑定到routingFirstQueue队列。secondRouting路由键绑定到routingSecondQueue队列。thirdRouting路由键绑定到routingThirdQueue队列。生成消息:@GetMapping("/routing-first")publicStringroutingFirst(){//使用不同的routingKey传递到不同的队列rabbitTemplate.convertAndSend("routingExchange","firstRouting","第一条路由消息");rabbitTemplate.convertAndSend("routingExchange","secondRouting","第二条路由消息");rabbitTemplate.convertAndSend("routingExchange","thirdRouting","第三条路由消息");return"ok";}消费消息:@RabbitListener(queues="routingFirstQueue")publicvoidroutingFirstListener(Stringmessage){System.out.println("【路由优先】"+message);}@RabbitListener(queues="routingSecondQueue")publicvoidroutingSecondListener(Stringmessage){System.out.println("【路由秒】"+message);}@RabbitListener(queues="routingThirdQueue")publicvoidroutingThirdListener(Stringmessage){System.out.println("【路由三】"+message);}输出:【路由第一】第一条路由消息【路由第二】第二条路由消息【路由第三】第三条路由消息分析:rabbitTemplate.convertAndSend("routingExchange","firstRouting","firstroutingmessage");该消息从生产者指定firstRouting路由键,找到对应的绑定队列routingFirstQueue,由routingFirstQueue队列消费。routingKey,如果要针对一类路由。例如:只接收.com结尾的消息。www.开头的消息。主题模式就派上用场了。路由模式和主题模式类似。路由模式是设置一个特定的routingKey绑定指定一个唯一的队列,而主题模式使用通配符匹配一个或多个队列。创建交换器和队列的代码示例:@BeanpublicQueuetopicFirstQueue(){returnnewQueue("topicFirstQueue");}@BeanpublicQueuetopicSecondQueue(){returnnewQueue("topicSecondQueue");}@BeanpublicQueuetopicThirdQueue(){returnnewQueue("topicThirdQueue");}@BeanpublicTopicExchangetopicExchange(){returnnewTopicExchange("topicExchange");}使用通配符绑定开关和开关:@BeanpublicBindingtopicFirstBind(){//.comendsreturnBindingBuilder.bind(topicFirstQueue()).to(topicExchange()).with("*.com");}@BeanpublicBindingtopicSecondBind(){//www.开头是returnBindingBuilder.bind(topicSecondQueue()).to(topicExchange()).with("www.#");}有两种通配符,*和#,*表示可以匹配一个。#表示可以进行多次匹配。例如:#.com表示接收多个以.com结尾的字段。例如:淘宝网、www.taobao.com、www.jd.com。*.com表示接受以.com结尾的字段。例如:淘宝网、京东。不能匹配多个字段,如www.taobao.com、cn.taobao.com。www.#可以匹配多个以www开头的字段。例如www.taobao,www.jd。www.*可以匹配以www.开头的字段。例如:www.taobao、www.jd。不能匹配多个字段,如www.taobao.com、www.jd.com。制作消息:@GetMapping("/topic-first-send")publicStringtopicFirstSend(){rabbitTemplate.convertAndSend("topicExchange","www.taobao.com","www.taobao.com");rabbitTemplate.convertAndSend("topicExchange","taobao.com","taobao.com");rabbitTemplate.convertAndSend("topicExchange","www.jd","www.jd");return"topicok";}消费消息:@RabbitListener(queues="topicFirstQueue")publicvoidtopicFirstListener(Stringmessage){System.out.println("【主题优先】"+message);}@RabbitListener(queues="topicSecondQueue")publicvoidtopicSecondListener(Stringmessage){System.out.println("【主题二】"+message);}输出:【主题二】www.taobao.com【主题一】taobao.com【主题二】www.jdwww.#可以匹配多个www.以开头的路由键,如www.taobao.com、www.jd。而*.com只能匹配以.com结尾的routingkey,比如taobao.com,不能匹配www.taobao.com。6、RPC方式消息具有返回值特性。PRC模式与上述模式的唯一区别在于,该模式可以接收来自消费者的返回值。生产者接收来自消费者的返回值。代码示例消费者端添加返回值:@RabbitListener(queuesToDeclare=@Queue("rpcQueue"))publicStringrpcListener(Stringmessage){System.out.println("【rpcreceivesmessage】"+message);return"rpcreturns"+message;}生产者发送消息:@GetMapping("/rpc-send")publicvoidrpcSend(){Objectreceive=rabbitTemplate.convertSendAndReceive("rpcQueue","rpcsendmessage");System.out.println("【发送消息消息】"+receive);}Output:[rpcreceivesmessage]rpcsendmessage[sendreceivesmessage]rpcreturnsrpcsendmessage订阅发布模式、路由模式和主题模式在开关类型上使用不同开关有:直接开关直接扇区开关扇出主题开关TopicDirectexchange(直连)directswitch应用于路由模式,switch需要通过特定的routingKey绑定queue,switch只有收到匹配的routingKey才会将消息转发到对应的queue,否则消息不会被转发转发。路由模式使用的是directswitch,在这种模式下,根据routingKey绑定一个特定的queue。FanoutExchange(fan-shaped)扇形交换机没有路由键的概念,只是将队列绑定到交换机上,发送到交换机的消息会转发到交换机绑定的队列中,类似于广播,只要你打开收音机,你就可以收到它广播的信息。扇区开关用于发布-订阅模式。TopicExchange(主题)主题模式是将路由键按照一个主题进行分类。与直连模式的区别在于,直连模式绑定了一个特定的routingkey,而topic模式使用通配符来绑定routingkey。绑定键有两个Species:*表示只能匹配一个。#表示可以匹配零个或多个。总结整合SpringBoot实现RabbitMQ的六种工作模式,详细讲解RabbitMQ的六种工作模式:简单模式不需要创建switch,匹配生产端和消费端的routingKey即可。工作模式多个消费者公平竞争同一条消息。发布-订阅模式一次向多个消费者发送消息。路由模式根据特定的路由键转发消息。主题模式根据通配符匹配路由键转发消息。RPC方式生产者接收消费者发送的返回值。源码示例https://github.com/jeremylai7/springboot-learning/tree/master/spring-rabbitmq/src/main/java/com/jeremy/pattern参考RabbitMQ介绍和六种工作模式解释四种开关兔MQ