springboot整合rabbitmq實戰,topic,direct,fanout模式詳情及實例。

springboot整合rabbitmq實戰,各類模式詳情及實例。

大家好,我是酷酷的韓~

版權聲明:本文爲博主(酷酷的韓)原創文章,未經博主允許不得轉載

在這裏插入圖片描述
一.RabbitMQ簡介.

RabbitMQ是採用Erlang語言實現AMQP(Advanced Message Queuing Protocol,高級消息隊列協議)的消息中間件,它最初起源於金融系統,用於在分佈式系統中存儲轉發消息。(這是百度來的,簡單來說就是用作信息轉發的消息中間件,下面將會從簡介到實例實戰進行分享)

二.什麼是消息中間件?

1.消息中間件是消息傳輸過程中保存消息的容器,提供路由,保證信息傳遞,即使消費者出問題,消息仍然保存一直等到被消費,但保存消息時間也是有期限的。
2.採用異步處理方式:發送消息無需等待反應結果。
3.應用程序之間爲松耦合關係,發送者和接受者不必去了解對方,只需要確認消息,過分些說,發送者和接收者不必同時在線,各自做自己的事情就可以啦。

三.RabbitMQ使用場景?

1.比如註冊賬號時需要發短信或者郵箱短信去認證,此時將發送短信或者郵箱短信發入隊列中,任去消費即可,這是異步處理得一個例子。
2.比如在電商中,訂單和庫存。在傳統模式中,比如提交個訂單,訂單會先記錄信息然後將信息發到庫存,庫存處理完然後才能返回結果,這需要一段較長時間(程序眼中),這時採用rabbitmq中間件,生成訂單不需要再去將信息發到庫存了,只需要拋到隊列中,任去消費即可。節省時間,加強用戶體驗。
3. 流量削峯,在秒殺場景中一般在秒殺活動中應用廣泛,在秒殺活動中一般會因爲流量過大,導致應用掛掉。爲了解決這個問題,一般在應用前端加入消息隊列。用戶請求,服務器收到後,首先寫入消息隊列,加入消息隊列長度超過最大值,則直接拋棄用戶請求跳轉到失敗頁面(這就是大家秒殺失敗的原因,哈哈哈哈哈哈)。

四.RabbitMQ概念說明。

Broker:消息隊列服務器實體。
Exchange:消息轉換機,消息轉發通過這個進行,它指定消息按照什麼規則,路由到哪個隊列。
Queue:消息隊列載體。
Binding:作用是將Exchange和Queue按照路由規則綁定起來,形成某種關係。
Routing key:路由關鍵字,exchange通過這個關鍵字進行消息投遞。
vhost:虛擬主機,一個broker可以開設多個vhost,用作不同用戶的權限分離。
producter:消息生產者,可以投遞消息的程序。
consumer:消息消費者,接受消息的程序。
channel:消息通道,在客戶端每個連接裏,可建立多個channel,每個channel代表一個會話任務。

五.RabbitMQ各類模式詳解。

1.direct(直連)
直連模式 一對一的綁定關係, Routing key(路由關鍵字)和Binding key只有完全匹配,才能消費成功。
2.fanout (廣播)
發送到該交換機的所有信息都將轉發到與該exchange綁定的queue中。
3.topic
在exchange中routing key 和binding key相匹配就可以綁定成功,可以一對一也可一對多。
bingding key 可以存在兩種特殊字符,# :匹配一個或多個單詞。 *:匹配一個單詞。
4.headers
Exchange不依賴於routing key與binding key的匹配規則來路由消息,而是根據發送的消息內容中的headers屬性進行匹配。

六.RabbitMQ各類模式實例。

1.引入pom文件。

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

2.topic爲例(其它的與其模式相同,路由綁定key和綁定key不同)
(1)生產者
發送類:

 @Component
@Slf4j
public class TestTopicSender {
    /**
     * 自動注入RabbitTemplate模板類
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 發送消息方法調用: 構建Message消息
     *
     * @param message
     * @param properties
     * @throws Exception
     */
    public void send(Object message, Map<String, Object> properties) throws Exception {
        MessageHeaders mhs = new MessageHeaders(properties);
        Message msg = MessageBuilder.createMessage(message, mhs);
        rabbitTemplate.setConfirmCallback(confirmCallback);
        rabbitTemplate.setReturnCallback(returnCallback);
        //id + 時間戳 全局唯一
        CorrelationData correlationData = new CorrelationData(System.currentTimeMillis() + "");
        rabbitTemplate.convertAndSend(TestTopicConfig.EXCHANGE, TestTopicConfig.ROUTINGKEY_V1, msg, correlationData);
    }


    /**
     * 回調函數: confirm確認
     */
    final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
        @Override
        public void confirm(CorrelationData correlationData, boolean ack, String cause) {
            log.info("correlationData:{}; ack:{}; cause:{}", correlationData, ack, cause);
            if (!ack) {
                log.error("回調函數: confirm確認異常correlationData:{}; ack:{}; cause:{}", correlationData, ack, cause);
            }
        }
    };

    /**
     * 回調函數: return返回
     */
    final RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
        @Override
        public void returnedMessage(org.springframework.amqp.core.Message message, int replyCode, String replyText,
                                    String exchange, String routingKey) {
            log.info("return exchange: " + exchange + ", routingKey: "
                    + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
        }
    };

配置類:

//交換機名稱
public final static String EXCHANGE = "test-Exchanges";
//路由key
public final static String ROUTINGKEY_V1 = "test-V1.hjq";
public final static String ROUTINGKEY_V2 = "test-V2.hjq";
//隊列名稱
public final static String QUEUE = "queue-test";
//是否持久化
public final static String DERABLE = "true";
//消息路由規則
public final static String TYPE = "topic";
// 忽略聲明異常
public final static String IGNOREDECEXCEPTION = "true";
/**
 *  綁定的路由鍵或模式。
 *      *(星號):可以(只能)匹配一個單詞
 *       #(井號):可以匹配多個單詞(或者零個)
 */
public final static String KEY_V1 = "test-V1.#";
public final static String KEY_V2 = "test-V2.#";

定時器發送:

@Service
@Slf4j
public class TestScheduleService {
    @Autowired
    private TestTopicSender testTopicSender;

    @Scheduled(cron = "0/10 * * * * ?  ")
    public void test() {
        System.out.println("11");
        TestVo testVo = new TestVo();
        testVo.setUuid(StrUtil.genUUID());
        try {
            testTopicSender.send(JSONObject.toJSONString(testVo), null);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

(2)消費者

@Component
@Slf4j
public class TestCustomerRecever {
    @Autowired
    @Qualifier(value = "dealDataLogTask")
    private DealDataLogTask dealDataLogTask;

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = TestTopicConfig.QUEUE,//隊列名稱
                    durable = TestTopicConfig.DERABLE),//是否持久化
            exchange = @Exchange(value = TestTopicConfig.EXCHANGE, //交換機名稱
                    durable = TestTopicConfig.DERABLE,//是否持久化o
                    type = TestTopicConfig.TYPE, //消息路由規則
                    ignoreDeclarationExceptions = TestTopicConfig.IGNOREDECEXCEPTION), // 忽略聲明異常
            key = TestTopicConfig.KEY_V1 // 綁定的路由鍵或模式。
    )
    )
    @RabbitHandler
    public void onMessage(Message message, Channel channel) throws Exception {
        log.info("消費端Payload: " + message.getPayload());
        Long deliveryTag = (Long) message.getHeaders().get(AmqpHeaders.DELIVERY_TAG);
        //TODO  處理業務邏輯
        String msg = (String) message.getPayload();
        dealTestMsg(msg);
        //手工ACK
        channel.basicAck(deliveryTag, false);
    }

    public void dealTestMsg(String text) {
        TestVo testVo = JSON.parseObject(text, TestVo.class);
        dealDataLogTask.doTestTask(testVo);
    }

配置類:

 //交換機名稱
    public final static String EXCHANGE = "test-Exchanges";
    //路由key
    public final static String ROUTINGKEY_V1 = "test-V1.hjq";
    public final static String ROUTINGKEY_V2 = "test-V2.hjq";
    //隊列名稱
    public final static String QUEUE = "queue-test";
    //是否持久化
    public final static String DERABLE = "true";
    //消息路由規則
    public final static String TYPE = "topic";
    // 忽略聲明異常
    public final static String IGNOREDECEXCEPTION = "true";
    /**
     *  綁定的路由鍵或模式。
     *      *(星號):可以(只能)匹配一個單詞
     *       #(井號):可以匹配多個單詞(或者零個)
     */
    public final static String KEY_V1 = "test-V1.#";
    public final static String KEY_V2 = "test-V2.#";

針對direct模式,在send類中將生產者和消費者路由綁定的key一致,fanout中在同一個exchange中即可。酷酷的韓一直在,有問題留言即可,我會第一時間看到回覆的。

你必須成功,因爲你不能失敗。------酷酷的韓

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