目錄
四、Springboot集成rabbitmq(確認消息返回)
一、簡單介紹
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瞭解哪條請求被成功執行了或執行失敗)