Spring Boot 註解方式 實現RabbitMQ

1.簡介

MQ爲message queue消息隊列,是程序與程序之間的通訊方法;
RabbitMQ是由erlang(面向併發的編程語言)語言進行開發,遵循的是AMQP(Advanced Message Queue )協議,支持市面上所有的主流的操作系統且支持多種語言開發

2.基礎概念
  1. Producer(生產者):生產者用於發佈消息。
  2. Consumer(消費者):用於從隊列中獲取消息,消費者只需關注隊列即可,不需要關注交換機和路由鍵。
  3. Queue(隊列):用於存儲消息,特性是先進先出,生產者生產的消息會發送到交換機中,交換機將消息存儲到某個或某些隊列中,最終被消費者消費。
  4. Exchange(交換機):生產者會將消息發送到交換機,然後交換機通過路由策略(規則)將消息路由到匹配的隊列中去。 Exchange不存儲消息,Exchange 常用的三種類型Fanout、Direct、Topic ,每種類型對應不同的路由規則。
  5. Routing Key(路由鍵):用於定義路由規則,當路由鍵和隊列綁定的路由鍵匹配時,消息就會發送到該隊列。
  6. Binding(綁定):以路由鍵爲規則將Exchange與Queue關聯起來(Exchange—>Routing Key—>Queue)
3.五種類型
  1. 簡答模式

在這裏插入圖片描述
使用默認的交換機,生產者直接把消息發送到Queue中,消費者從Queue中獲取消息。

  1. work模式

在這裏插入圖片描述
使用默認的交換機,多個消費者同時綁定一個隊列,隊列中的消息會被平攤給多個消費者,默認使用公平分發策略,效率高的就會一直空閒,效率低的一直忙,可以設置每次消費的數量使效率高的多消費

  1. 廣播模式(Fanout)
    在這裏插入圖片描述
    生產者把數據根據交換機的名稱推送到對應的交換機上,再把消息發送給與其綁定的所有隊列中,消費者在從對應的隊列中消費數據。(不管路由鍵,只需要綁定到交換機上)

  2. 路由模式(Direct)
    在這裏插入圖片描述
    生產者先把消息發送到交換機,交換機會根據路由規則(binding key與routing key完全匹配)發送到對應的隊列中去,消費者再去消費對應的消息(需要路由鍵完全匹配)

  3. 通配符模式(Topic)

在這裏插入圖片描述
與路由模式相同,只是在路由規則上進行了擴展,routing key跟binding key都是用 “.” 進行分割,分隔開的每一段字符串是一個單詞。
例: aaaaa.ndsds.dsad
binding key中有兩種特殊字符 “*”跟 ”#”,*用於匹配一個單詞,#可以匹配多個或零個單詞(路由鍵模糊匹配)

4.代碼演示
  1. 添加對應POM文件
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
  1. .在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);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章