RabbitMQ使用,與SpringBoot整合

介紹

RabbitMQ是一個消息代理:它接受和轉發消息。你可以將其視爲郵局:當你把你想要寄出的郵件放在一個郵箱裏時,你可以確定,郵遞員先生或女士最終會把郵件交給你的收件人。在這個類比中,RabbitMQ是一個郵箱,郵局和郵遞員


安裝

Rabbit MQ 是建立在強大的Erlang OTP平臺上,因此安裝RabbitMQ之前要先安裝Erlang

    下載Erlang:http://www.erlang.org/downloads 

    下載RabbitMQ:https://www.rabbitmq.com/download.html

下載安裝完成即可

使用web管理工具

運行命令:rabbitmq-plugins enable rabbitmq_management,即可開啓web管理插件

默認的端口是15672,通過http://localhost:15672即可訪問

默認的管理員賬戶密碼都是:guest

 


使用

rabbitMQ的官方文檔上共提供了6種使用方式:

 

下面將通過springboot(即 Spring AMQP)的方式來一一展示。

 

0.依賴以及配置

使用rabbitMQ只需要引入如下依賴即可:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

賬號配置:

默認端口是5672,虛擬主機爲/,賬戶爲guest,根據自己的情況填寫

spring.rabbitmq.host=localhost
spring.rabbitmq.virtual-host=/test
spring.rabbitmq.port=5672
spring.rabbitmq.username=test
spring.rabbitmq.password=test

1.Hello world模式

如圖所示,一個生產者將詳細發送到隊列中,消費者從隊列裏獲取消息。

1.1 定義一個隊列(也可以在RabbitMQ服務端創建隊列)

    @Bean
    public Queue myQueue() {
        return new Queue("test");
    }

1.2 定義一個生產者,將消息發送至隊列

package cn.coolwind.rabbitmqdemo.controller;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SenderController {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping("/hello")
    public Object hello() {
        String msg = "Hello World 消息發送!";
        rabbitTemplate.convertAndSend("test",msg);
        return msg;
    }
}

只需要使用  rabbitTemplate.convertAndSend("隊列名",發送的內容) 即可。

1.3 定義一個消費者,接收隊列裏的消息

package cn.coolwind.rabbitmqdemo.consumer;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class Consumer {

    @RabbitListener(queues = "test")
    public void helloWorldMsg(String msg) {
        System.out.println("helloWorld消費者接收到的消息:"+msg);
    }
}

只需要在處理消息的方法上加 @RabbitListener(queues = "隊列名")註解即可,方法裏的參數即爲接收到的消息。

1.4 運行

發送消息:

 

接收消息:


2.Work Queues模式

如圖所示,一個生產者將消息發送到隊列,可以由多個消費者來對隊列裏的消息進行消費,但每個消息只消費一次,即一條消息只有一個消費者處理。

2.1 定義一個生產者,向隊列發送消息

 

    @GetMapping("/work")
    public Object work() {
        StringBuffer msg = new StringBuffer();
        for (int i = 0; i < 10; i++) {
            String content = "第" + i + "條Work Queues消息發送!";
            rabbitTemplate.convertAndSend("workQueue",content);
            msg.append(content);
        }
        return msg;
    }

與helloworld模式的發送一致,這裏模擬發送10條消息。

2.2 定義消費者來接收消息

 

    @RabbitListener(queues = "workQueue")
    public void workMsg1(String msg) {
        System.out.println("Work消費者1:"+msg);
    }
    
    @RabbitListener(queues = "workQueue")
    public void workMsg2(String msg) {
        System.out.println("Work消費者2:"+msg);
    }

方式與helloworld模式相同,這裏定義了2個消費者來獲取消息

2.3運行

發送消息:

接收消息:

可以看出一條消息只會由一個消費者來消費,默認情況下,RabbitMQ將按順序將每條消息發送給下一個消費者。平均而言,每個消費者將獲得相同數量的消息。這種分發消息的方式稱爲循環法。


3.Publish/Subscribe模式

 

如圖所示,生產者先將消息發送至一個交換機X,然後交換機X將消息發送到選定的隊列裏(隊列1、隊列2...),最後由消費者去消費對應隊列裏的消息。

3.1 首先定義一個交換機

 使用new FanoutExchange("名字")創建一個交換機

    @Bean
    public FanoutExchange fanout() {
        return new FanoutExchange("publish");
    }

3.2 創建需要使用的隊列

 

    @Bean
    public Queue subscribe1() {
        return new AnonymousQueue();
    }

    @Bean
    public Queue subscribe2() {
        return new AnonymousQueue();
    }

3.3 將隊列與交換機綁定


    @Bean
    public Binding binding1(FanoutExchange fanout, Queue subscribe1) {
        return BindingBuilder.bind(subscribe1).to(fanout);
    }

    @Bean
    public Binding binding2(FanoutExchange fanout, Queue subscribe2) {
        return BindingBuilder.bind(subscribe2).to(fanout);
    }

3.4 生產者發送消息

同樣是使用rabbitTemplate.convertAndSend()方法,裏面的參數爲:

(String exchange, String routingKey, Object object),分別是(交換機名字,路由,需要發送的消息)


    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private FanoutExchange fanout;

    @GetMapping("/publish")
    public Object publish() {
        StringBuffer msg = new StringBuffer();
        for (int i = 0; i < 10; i++) {
            String content = "第" + i + "條publish消息發送!";
            rabbitTemplate.convertAndSend(fanout.getName(),"",content);
            msg.append(content).append("</br>");
        }
        return msg;
    }

 

3.5 消費者接受消息

同樣是使用之前的方式

    @RabbitListener(queues = "#{subscribe1.name}")
    public void publish1(String msg) {
        log.info("發佈訂閱模式-消費者1:"+msg);
    }

    @RabbitListener(queues = "#{subscribe2.name}")
    public void publish2(String msg) {
        log.info("發佈訂閱模式-消費者2:"+msg);
    }

 

3.6 運行

可以看到,兩個隊列裏的消費者都分別把消息接收了。(如果一個隊列裏有多個消費者的話,該隊列就會和之前的work模式一樣默認使用輪詢的機制接收消息)

 

 


 

4.Routing模式

如圖所示,生產者P將消息發送到交換機X,交換機X再根據對應的路由KEY(orange、black、green)來判斷髮送至哪一個隊列中(Q1、Q2),最後由相應的消費者(C1,C2)來進行消費。

4.1 首先定義一個交換機

使用new DirectExchange("名字"); 創建一個交換機


    @Bean
    public DirectExchange direct() {
        return new DirectExchange("direct");
    }

 

4.2 定義隊列

同3.2


    @Bean
    public Queue routingQueue1() {
        return new AnonymousQueue();
    }

    @Bean
    public Queue routingQueue2() {
        return new AnonymousQueue();
    }

 

4.3 綁定隊列與交換機


    @Bean
    public Binding bindRouting1AndQueue1(DirectExchange directExchange, Queue routingQueue1) {
        //隊列1與directExchange交換機綁定,並且接收routingKey爲“routing1”的消息
        return BindingBuilder.bind(routingQueue1).to(directExchange).with("routing1");
    }

    @Bean
    public Binding bindRouting1AndQueue2(DirectExchange directExchange, Queue routingQueue2) {
        //隊列2與directExchange交換機綁定,並且接收routingKey爲“routing1”的消息
        return BindingBuilder.bind(routingQueue2).to(directExchange).with("routing1");
    }

    @Bean
    public Binding bindRouting2AndQueue2(DirectExchange directExchange, Queue routingQueue2) {
        //隊列2與directExchange交換機綁定,並且接收routingKey爲“routing2”的消息
        return BindingBuilder.bind(routingQueue2).to(directExchange).with("routing2");
    }

4.4 生產者發送消息

同樣是使用rabbitTemplate.convertAndSend()方法,裏面的參數爲:

(String exchange, String routingKey, Object object),分別是(交換機名字,路由,需要發送的消息)

 


    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Autowired
    private DirectExchange direct;

    @GetMapping("/routing")
    public Object routing() {
        StringBuffer msg = new StringBuffer();
        for (int i = 0; i < 10; i++) {
            String content = "第" + i + "條routing1消息發送!";
            String content2 = "第" + i + "條routing2消息發送!";
            rabbitTemplate.convertAndSend(direct.getName(),"routing1",content);
            rabbitTemplate.convertAndSend(direct.getName(),"routing2",content2);
            msg.append(content).append("</br>").append(content2).append("</br>");
        }
        return msg;
    }

4.5 消費者接受消息

與之前相同


    @RabbitListener(queues = "#{routingQueue1.name}")
    public void routing1(String msg) {
        log.info("queue1接收到的消息:"+msg);
    }

    @RabbitListener(queues = "#{routingQueue2.name}")
    public void routing2(String msg) {
        log.info("queue2接收到的消息:"+msg);
    }

4.6 運行結果

隊列1只綁定了routing1,隊列2綁定了routing1,routing2;

所以隊列1只接受到了routing1的消息,而隊列2兩個消息都收到了


5 Topics 模式

topics 模式是routing模式的升級版,也就是將routing模式中的key變成了通配符的形式(圖中的:*.orange.* 、*.*.rabbit、lazy.#)。使用方式與routing模式大同小異。

以下只列出有差異的代碼,步驟與之前的事例相同,可以從之前的代碼類推

    @Bean
    public TopicExchange topic() {
        return new TopicExchange("topic");
    }


    @Bean
    public Binding bindTopic1AndQueue1(TopicExchange topicExchange, Queue topicQueue1) {
        //隊列1與directExchange交換機綁定,並且接收topicKey爲“*.*.topic1”的消息
        return BindingBuilder.bind(topicQueue1).to(topicExchange).with("*.*.topic1");
    }


//發送消息時使用:第二個參數與綁定時的“*.*.topic1”相對應
   rabbitTemplate.convertAndSend(topic.getName(),"a.b.topic1",content);

代碼:https://github.com/fi00wind/rabbitmq-demo

 

 

 

 

 

 

 

 

 

 

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