1.簡介
MQ爲message queue消息隊列,是程序與程序之間的通訊方法;
RabbitMQ是由erlang(面向併發的編程語言)語言進行開發,遵循的是AMQP(Advanced Message Queue )協議,支持市面上所有的主流的操作系統且支持多種語言開發
2.基礎概念
- Producer(生產者):生產者用於發佈消息。
- Consumer(消費者):用於從隊列中獲取消息,消費者只需關注隊列即可,不需要關注交換機和路由鍵。
- Queue(隊列):用於存儲消息,特性是先進先出,生產者生產的消息會發送到交換機中,交換機將消息存儲到某個或某些隊列中,最終被消費者消費。
- Exchange(交換機):生產者會將消息發送到交換機,然後交換機通過路由策略(規則)將消息路由到匹配的隊列中去。 Exchange不存儲消息,Exchange 常用的三種類型Fanout、Direct、Topic ,每種類型對應不同的路由規則。
- Routing Key(路由鍵):用於定義路由規則,當路由鍵和隊列綁定的路由鍵匹配時,消息就會發送到該隊列。
- Binding(綁定):以路由鍵爲規則將Exchange與Queue關聯起來(Exchange—>Routing Key—>Queue)
3.五種類型
- 簡答模式
使用默認的交換機,生產者直接把消息發送到Queue中,消費者從Queue中獲取消息。
- work模式
使用默認的交換機,多個消費者同時綁定一個隊列,隊列中的消息會被平攤給多個消費者,默認使用公平分發策略,效率高的就會一直空閒,效率低的一直忙,可以設置每次消費的數量使效率高的多消費
-
廣播模式(Fanout)
生產者把數據根據交換機的名稱推送到對應的交換機上,再把消息發送給與其綁定的所有隊列中,消費者在從對應的隊列中消費數據。(不管路由鍵,只需要綁定到交換機上) -
路由模式(Direct)
生產者先把消息發送到交換機,交換機會根據路由規則(binding key與routing key完全匹配)發送到對應的隊列中去,消費者再去消費對應的消息(需要路由鍵完全匹配) -
通配符模式(Topic)
與路由模式相同,只是在路由規則上進行了擴展,routing key跟binding key都是用 “.” 進行分割,分隔開的每一段字符串是一個單詞。
例: aaaaa.ndsds.dsad
binding key中有兩種特殊字符 “*”跟 ”#”,*用於匹配一個單詞,#可以匹配多個或零個單詞(路由鍵模糊匹配)
4.代碼演示
- 添加對應POM文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- .在properties中加入對應的配置
spring.rabbitmq.host=
spring.rabbitmq.port=
spring.rabbitmq.username=
spring.rabbitmq.password=
spring.rabbitmq.virtual-host=
#每次從隊列中取一個,輪詢分發,默認是公平分發
spring.rabbitmq.listener.simple.prefetch=1
#失敗後重試
spring.rabbitmq.listener.simple.default-requeue-rejected=true
簡單模式生產者
@RestController
@Slf4j
@RequestMapping("SimpleSender")
public class SimpleSender {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping("simple")
public void simpleSend(String content){
log.info("簡單隊列發送消息:{}",content);
this.amqpTemplate.convertAndSend("simple",content);
}
}
簡單模式消費者
@Component
@Slf4j
public class SimpleReceiver {
//監聽simple隊列,如果沒有此隊列先進性創建 簡單隊列消費者 返回值必須void
@RabbitListener(queuesToDeclare =@Queue("simple") )
@RabbitHandler
public void SimpleReceiver(String conten){
log.info("開始消費簡單隊列消息:{}",conten);
}
}
work模式生產者
@RestController
@Slf4j
@RequestMapping("WorkSender")
public class WorkSender {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping("workSender")
public void workSender(String content){
log.info("work模式發送消息:{}",content);
this.amqpTemplate.convertAndSend("work",content);
}
}
work模式消費者
@Slf4j
@Component
//放在類上,監聽到消息後會交給@RabbitHandler的方法進行處理,如果有多個方法,會根據參數類型進行選擇
//@RabbitListener(queuesToDeclare = @Queue("work") )
public class WorkReceiver {
@RabbitListener(queuesToDeclare = @Queue("work"))
@RabbitHandler
public void workReceiver1(String content) throws InterruptedException {
log.info("work模式開始消費1:{}",content);
Thread.sleep(1000);
}
@RabbitListener(queuesToDeclare = @Queue("work") )
@RabbitHandler
public void workReceiver2(String content, Channel channel) throws IOException, InterruptedException {
log.info("work模式開始消費2:{}",content);
Thread.sleep(2000);
}
}
廣播模式生產者
@RestController
@Slf4j
@RequestMapping("FanoutSender")
public class FanoutSender {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping("fanoutSender")
public void fanout(String content){
log.info("fanout開始廣播數據:{}",content);
this.amqpTemplate.convertAndSend("fanout.test","",content);
}
}
廣播模式消費者
@Slf4j
@Component
public class FanoutReceiver {
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue("fanout1"),
exchange = @Exchange("fanout.test")
))
public void fanoutReceiver2(String content){
log.info("廣播模式1開始消費:{}",content);
}
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue("fanout2"),
exchange = @Exchange("fanout.test")
))
public void fanoutReceiver1(String content){
log.info("廣播模式2開始消費:{}",content);
}
路由模式生產者
@Slf4j
@RestController
@RequestMapping("DirectSender")
public class DirectSender {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping("directSender")
public void directSender(String content,String key){
log.info("路由模式開始生產消息:{},key:{}",content,key);
this.amqpTemplate.convertAndSend("direct.test",key,content);
}
}
路由模式消費者
@Slf4j
@Component
public class DirectReceiver {
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct1"),
exchange = @Exchange("direct.test"),
key = "a"
))
public void directReceiver1(String content){
log.info("路由模式1開始消費,{}",content);
}
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct2"),
exchange = @Exchange("direct.test"),
key = "b"
))
public void directReceiver2(String content){
log.info("路由模式2開始消費,{}",content);
}
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct3"),
exchange = @Exchange("direct.test"),
key = "b"
))
public void directReceiver3(String content){
log.info("路由模式3開始消費,{}",content);
}
}
通配符模模式配置類
@Configuration
public class TopicConfig {
@Bean
public Queue topic1() {
return QueueBuilder.durable("topic1").build();
}
@Bean
public Queue topic2() {
return new Queue("topic2");
}
@Bean
public Queue topic3() {
return new Queue("topic3");
}
@Bean
public Queue topic4() {
return new Queue("topic4");
}
@Bean
public TopicExchange topicExchange() {
return new TopicExchange("topic.test");
}
@Bean
public Binding binding1(@Qualifier("topic1") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange) {
return BindingBuilder.bind(queue).to(topicExchange).with("a.#");
}
@Bean
public Binding binding2(@Qualifier("topic2") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange) {
return BindingBuilder.bind(queue).to(topicExchange).with("a.*");
}
@Bean
public Binding binding3(@Qualifier("topic3") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange) {
return BindingBuilder.bind(queue).to(topicExchange).with("*.a");
}
@Bean
public Binding binding4(@Qualifier("topic4") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange) {
return BindingBuilder.bind(queue).to(topicExchange).with("#.a");
}
}
通配符模式生產者
@Slf4j
@RestController
@RequestMapping("TopicSender")
public class TopicSender {
@Autowired
private AmqpTemplate amqpTemplate;
@GetMapping("topicSender")
public void toipc(String content,String key){
log.info("通配符模式開始發佈消息:{},key:{}",content,key);
this.amqpTemplate.convertAndSend("topic.test",key,content);
}
}
通配符模式消費者
@Slf4j
@Component
@Configuration
public class TopicReceiver {
@RabbitHandler
@RabbitListener(queues = "topic1")
public void topicReceiver1(String content){
log.info("通配符模式1開始訂閱:{}",content);
}
@RabbitHandler
@RabbitListener(queues = "topic2")
public void topicReceiver2(String content){
log.info("通配符模式2開始訂閱:{}",content);
}
@RabbitHandler
@RabbitListener(queues = "topic3")
public void topicReceiver3(String content){
log.info("通配符模式3開始訂閱:{}",content);
}
@RabbitHandler
@RabbitListener(queues = "topic4")
public void topicReceiver4(String content){
log.info("通配符模式4開始訂閱:{}",content);
}
}