RabbitMQ學習總結-確認消息返回

目錄

一、簡單介紹

二、幾個名詞

三、四種模式

四、Springboot集成rabbitmq(確認消息返回)

五、rabbitmq延時隊列使用

六、rabbitmq實現rpc調用


一、簡單介紹

      RabbitMQ是實現了高級消息隊列協議(AMQP)的開源消息代理軟件(亦稱面向消息的中間件)。RabbitMQ服務器是用Erlang語言編寫的,可持久化。

二、幾個名詞

      消費者:發送消息一方。

      交換機(Exchange):生產者發送消息首先到交換機上,然後根據綁定的key找到對應的隊列。

      綁定Key:交換機和消息隊列兩者之間緊緊聯繫的樞紐。

      消息隊列(Queue):消費者從消息隊列取出消息。

      消費者:消費者一方。

三、四種模式

      1.Direct Exchange:根據綁定key全文匹配去尋找隊列 。

      2.Topic Exchange:根據綁定key模糊匹配去尋找隊列 。(“*”:匹配一個詞;“#”:匹配多個詞;舉例:key.*   key.#)

      3.Headers Exchange:headers 也是根據規則匹配, 相較於 direct 和 topic 固定地使用 routing_key , headers 則是一個自定義匹配規則的類型。在隊列與交換器綁定時, 會設定一組鍵值對規則, 消息中也包括一組鍵值對( headers 屬性), 當這些鍵值對有一對, 或全部匹配時, 消息被投送到對應隊列。

      4.Fanout Exchange:廣播形式,所有隊列都會收到,可用於批量發送短息或郵件。

四、Springboot集成rabbitmq(確認消息返回)

<!-- 添加springboot對amqp的支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
spring:
   rabbitmq:
      host: localhost
      port: 5672
      username: guest
      password: guest
      publisher-confirms: true #開啓消息確認
      publisher-returns: true  #開啓消息發送到隊列失敗返回
      listener:
         direct:
            acknowledge-mode: MANUAL #開啓direct模式下手動返回
         simple:
            acknowledge-mode: MANUAL  #開啓所有模式下手動返回

採用topic模式

package com.order.config;

import javax.annotation.PostConstruct;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Configuration
@Component
public class MQSenderConfig  implements ConfirmCallback,ReturnCallback{
	@Autowired
    private RabbitTemplate rabbitTemplate;
	
	@PostConstruct
	public void init(){
		rabbitTemplate.setReturnCallback(this);
		rabbitTemplate.setConfirmCallback(this);
	}
	
	@Bean(name="orderCart")
    public Queue queueMessage() {
        return new Queue("createCart");
    }

    @Bean(name="productSku")
    public Queue queueMessages() {
        return new Queue("updateProStock");
    }

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

    @Bean
    Binding bindingExchangeMessage(@Qualifier("orderCart") Queue queueMessage, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessage).to(exchange).with("createCart");
    }

    @Bean
    Binding bindingExchangeMessages(@Qualifier("productSku") Queue queueMessages, TopicExchange exchange) {
        return BindingBuilder.bind(queueMessages).to(exchange).with("updateProStock");//*表示一個詞,#表示零個或多個詞
    }
    

	@Override
	//如果消息沒有到exchange,則confirm回調,ack=false
	//如果消息到達exchange,則confirm回調,ack=true
	//消費者手動進行確認
	public void confirm(CorrelationData correlationData, boolean ack, String cause) {
		if (ack) {
			log.info("消息id:" + correlationData.getId()+"------消息發送確認成功");
		} else {
			log.info("消息id:" + correlationData.getId()+"------消息發送確認失敗:" + cause);
		}
	}

	@Override
	//exchange到queue成功,則不回調return
	//exchange到queue失敗,則回調return(需設置mandatory=true,否則不回回調,消息就丟了)
	public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
		log.info("消息主體 message : "+message);
		log.info("消息主體 replyCode : "+ replyCode);
		log.info("描述:"+ replyText);
		log.info("消息使用的交換器 exchange : "+ exchange);
		log.info("消息使用的路由鍵 routing : "+ routingKey);
	}
}

消費者

package com.order.config;

import java.io.IOException;

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import com.common.util.JsonMapUtils;
import com.domain.order.OrderCart;
import com.order.service.impl.OrderCartServiceImpl;
import com.rabbitmq.client.Channel;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class MQReceiverConfig{
	@Autowired
	private OrderCartServiceImpl orderCartService;
	
	@RabbitListener(queues = "createCart") // 監聽器監聽指定的Queue
    public void createCart(Channel channel, Message message)  {
        try {
        	OrderCart cart =(OrderCart) JsonMapUtils.toObject(message.getBody());
        	orderCartService.insertSelective(cart);
        	log.info("執行加入購物車消息成功");
        } catch (Exception e) {
            log.error("執行加入購物車消息失敗-----" + e.getMessage());
            //丟棄這條消息
            //channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
            
            //記錄日誌失敗原因
            
        }finally {
        	//告訴服務器收到這條消息 已經被我消費了 可以在隊列刪掉 這樣以後就不會再發了 否則消息服務器以爲這條消息沒處理掉 後續還會在發
            try {
				channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
			} catch (IOException e) {
				log.error("回執加入購物車消息失敗---" + e.getMessage());
			}
		}
 
    }

}

生產者

//cart 發送內容
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
template.convertAndSend("exchange", "createCart", cart, correlationId);

五、rabbitmq延時隊列使用

      不裝插件會報錯

connection error; protocol method: #method(reply-code=503, reply-text=COMMAND_INVALID - unknown exchange type 'x-delayed-message', class-id=40, method-id=10)

     需裝插件-官網:https://www.rabbitmq.com/blog/2015/04/16/scheduling-messages-with-rabbitmq/

     目前最新版插件地址:https://dl.bintray.com/rabbitmq/community-plugins/3.7.x/rabbitmq_delayed_message_exchange/

     放入地址

/usr/local/Cellar/rabbitmq/3.7.7_1/plugins 

     執行命令生效,不需要重啓

/usr/local/Cellar/rabbitmq/3.7.7_1/sbin/rabbitmq-plugins enable rabbitmq_delayed_message_exchange

    交換機設置類型

@Bean
    public TopicExchange exchangeDelay() {
    	TopicExchange topicExchange = new TopicExchange("exchange-delay");
    	topicExchange.setDelayed(true);
        return topicExchange;
    }

    生產者發送消息,加上延遲時間

CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
			//cart 轉遞參數內容
			template.convertAndSend("exchange-delay", "updateProStock", cart, message ->{
		        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
		        message.getMessageProperties().setDelay(1 * (60*1000));   // 毫秒爲單位,指定此消息的延時時長
		        return message;
		    },correlationId);

六、rabbitmq實現rpc調用

      客戶端發送請求(消息)時,在消息的屬性(MessageProperties,在AMQP協議中定義了14中properties,這些屬性會隨着消息一起發送)中設置兩個值replyTo(一個Queue名稱,用於告訴服務器處理完成後將通知我的消息發送到這個Queue中)和correlationId(此次請求的標識號,服務器處理完成後需要將此屬性返還,客戶端將根據這個id瞭解哪條請求被成功執行了或執行失敗)

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