RabbitMQ消息隊列實戰指南

RabbitMQ 是什么?

RabbitMQ是一個遵循AMQP協議的消息中間件,它從生產者接收消息并傳遞給消費者,在這個過程中,根據路由規則進行消息的路由、緩存和持久化。

AMQP,高級消息隊列協議,是應用層協議的一個開放標準,為面向消息的中間件而設計的。基于此協議的客戶端與消息中間件可以傳遞消息,并不受客戶端/中間件不同產品,不同的開發語言等條件的限制。RabbitMQ就是通過Erlang語言實現的一種消息中間件。

具備下面的核心功能:

  1. 異步通信:允許應用程序通過消息隊列解耦,生產者發送消息后無需等待消費者處理。
  2. 消息路由:通過靈活的交換器(Exchange)機制,支持多種消息分發模式。
  3. 可靠性保障:提供消息持久化、確認機制(ACK)和重試策略,確保消息不丟失。
  4. 負載均衡:通過輪詢或權重分配方式將消息分發給多個消費者,提升系統吞吐量。

為什么需要消息隊列?

在分布式系統中,直接調用(如 HTTP 請求)可能導致以下問題:

  • 耦合性高:服務之間依賴性強,一個服務故障可能引發雪崩效應。
  • 性能瓶頸:同步調用會阻塞線程,影響系統響應速度。
  • 擴展困難:高并發場景下難以動態調整消費者數量。

消息隊列通過異步通信緩沖機制解決了這些問題:生產者發送消息到隊列后即可返回,消費者按自身能力處理消息。即使消費者暫時不可用,消息仍能存儲在隊列中,避免數據丟失。

核心概念 :

名稱

說明

Producer

生產者,發送消息的一方

Consumer

消費者,接收消息的一方

Queue

隊列,存儲消息的緩沖區

Exchange

交換機,負責轉發消息到隊列

Routing Key

路由鍵,決定消息如何路由

Binding

綁定,連接交換機與隊列的規則

Message

消息,最終傳輸的數據

工作模型 :

模型類型(英文)

中文名稱

簡介

Simple

簡單隊列模型

一個生產者對應一個隊列和一個消費者,最基礎的模型,適合入門學習或簡單通信。

Work Queue

工作隊列模型

一個生產者將任務發送到隊列,由多個消費者競爭消費,常用于任務分發和后臺處理。

Publish/Subscribe

發布/訂閱模型

通過 fanout 類型交換機,生產者發送的消息會廣播到所有綁定的隊列,適合通知、廣播類場景。

Routing

路由模型

使用 direct 類型交換機,生產者根據路由鍵將消息精確投遞到指定隊列,適合日志分級處理等場景。

Topics

主題(通配路由)模型

使用 topic 類型交換機,支持模糊匹配路由鍵(如 user.*.email),適合復雜業務訂閱場景。

RPC 模式

遠程調用模型

實現遠程服務調用,生產者發送請求并等待消費者返回響應,適合系統之間的異步調用場景。

Docker安裝RabbitMQ

1、拉取RabbitMQ鏡像

命令:

docker pull rabbitmq

2、啟動

docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq

3、進入容器內部

docker exec -it rabbit /bin/bash

4、安裝插件

rabbitmq-plugins enable rabbitmq_management

5、查看插件情況

rabbitmq-plugins list

6、訪問RabbitMQ

http://192.168.142.3:15672/

賬號:guest

密碼:guest

RabbitMQ安裝方式解壓安裝

1、下載RabbitMQ

Installing RabbitMQ | RabbitMQ

2、下載Erlang

RabbitMQ是采用 Erlang語言開發的,所以系統環境必須提供 Erlang環境,需要是安裝 Erlang

ErlangRabbitMQ版本對照:https://www.rabbitmq.com/which-erlang.html

這里安裝最新版本3.8.14的RabbitMQ,對應的Erlang版本推薦23.x

下載地址:el/7/erlang-23.2.7-2.el7.x86_64.rpm - rabbitmq/erlang · packagecloud

3、將下載好的文件上傳到服務器

# 創建文件
mkdir -p /opt/rabbitmq

將安裝包上傳到/opt/rabbitmq

4、安裝Erlang

cd /opt/rabbitmq
# 解壓
rpm -Uvh erlang-23.2.7-2.el7.x86_64.rpm# 安裝
yum install -y erlang

如果yum無法使用:
使用國內鏡像源(適用于中國用戶)
  1. 備份原有 repo 文件:
sudo mkdir /etc/yum.repos.d/backup
sudo mv /etc/yum.repos.d/CentOS-* /etc/yum.repos.d/backup/
  1. 下載阿里云鏡像源:
sudo curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
  1. 清理并重建緩存:
sudo yum clean all
sudo yum makecache

安裝完成后輸入如下指令查看版本號輸入兩次ctrl+c退出

5、安裝RabbitMQ

RabiitMQ安裝過程中需要依賴socat插件,首先安裝該插件

yum install -y socat

解壓安裝RabbitMQ的安裝包

# 解壓
rpm -Uvh rabbitmq-server-3.8.14-1.el7.noarch.rpm
# 安裝
yum install -y rabbitmq-server

6、啟動RabbitMQ服務

# 啟動rabbitmq
systemctl start rabbitmq-server
# 查看rabbitmq狀態
systemctl status rabbitmq-server# 其他命令
# 設置rabbitmq服務開機自啟動
systemctl enable rabbitmq-server
# 關閉rabbitmq服務 
systemctl stop rabbitmq-server 
# 重啟rabbitmq服務 
systemctl restart rabbitmq-server

7、RabbitMQWeb管理界面及授權操作

systemctl stop firewalld
# 打開RabbitMQWeb管理界面插件
rabbitmq-plugins enable rabbitmq_management

打開瀏覽器,訪問服務器公網ip:15672 http://192.168.142.131:15672/

rabbitmq有一個默認的賬號密碼guest

添加遠程用戶

# 添加用戶
rabbitmqctl add_user 用戶名 密碼
rabbitmqctl add_user admin 123456
# 設置用戶角色,分配操作權限 
rabbitmqctl set_user_tags 用戶名 角色
rabbitmqctl set_user_tags admin administrator
# 為用戶添加資源權限(授予訪問虛擬機根節點的所有權限) 
rabbitmqctl set_permissions -p / 用戶名 ".*" ".*" ".*"
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"#其他指令
# 修改密碼
rabbitmqctl change_ password 用戶名 新密碼
# 刪除用戶
rabbitmqctl delete_user 用戶名
# 查看用戶清單
rabbitmqctl list_users

角色有四種

  • administrator:可以登錄控制臺、查看所有信息、并對rabbitmq進行管理
  • monToring:監控者;登錄控制臺,查看所有信息
  • policymaker:策略制定者;登錄控制臺指定策略
  • managment:普通管理員;登錄控制

創建用戶admin,密碼123456,設置administrator角色,賦予所有權限

然后訪問 http://192.168.142.131:15672/ 用戶名:admin 密碼:123456

8、延時隊列插件安裝

Community Plugins | RabbitMQ(RabbitMQ是什么版本的,下載的插件就得是什么版本的)

將插件上傳到/usr/lib/rabbitmq/lib/rabbitmq_server-3.8.14/plugins

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

然后重啟rabbitMQ

SpringBoot如何使用RabbitMQ

1、創建SpringBoot項目引入依賴

<!-- Spring Boot Starter for RabbitMQ -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2、在 application.yml 中添加 RabbitMQ 配置

spring:# RabbitMQ 相關配置rabbitmq:# RabbitMQ 服務器地址host: 192.168.142.131# RabbitMQ 服務器端口 客戶端應用程序(生產者/消費者)通過這個端口與 RabbitMQ 服務器交互port: 5672# RabbitMQ 用戶名username: admin# RabbitMQ 密碼password: 123456# RabbitMQ 虛擬主機virtual-host: /# 開啟發送方確認機制publisher-confirm-type: correlated# 開啟發送方退回機制publisher-returns: true# RabbitMQ 模板配置template:# 設置為 true 時,RabbitMQ 將確認消息是否成功投遞到隊列mandatory: true# 消息監聽器配置listener:simple:# 消費者最小數量concurrency: 5# 消費者最大數量max-concurrency: 10# 每次從隊列中獲取的消息數量prefetch: 1# 消費者手動 ackacknowledge-mode: manual

3、創建 RabbitMQ 配置類

package com.lw.mqdemo.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.HashMap;
import java.util.Map;/*** RabbitMQ配置類,用于聲明隊列、交換機、綁定關系以及配置消息轉換器和RabbitTemplate*/
@Slf4j
@Configuration
public class RabbitMQConfig {// 定義隊列、交換機和路由鍵名稱// 定義直連交換機相關的常量// 隊列名稱public static final String DIRECT_QUEUE = "test.direct.queue";// 交換機名稱public static final String DIRECT_EXCHANGE = "test.direct.exchange";// 路由鍵名稱public static final String DIRECT_ROUTING_KEY = "test.direct.routingkey";// 定義主題交換機相關的常量// 隊列1名稱public static final String TOPIC_QUEUE_1 = "test.topic.queue1";// 隊列2名稱public static final String TOPIC_QUEUE_2 = "test.topic.queue2";// 交換機名稱public static final String TOPIC_EXCHANGE = "test.topic.exchange";// 路由鍵名稱public static final String TOPIC_ROUTING_KEY_1 = "test.topic.routingkey1";// 路由鍵名稱public static final String TOPIC_ROUTING_KEY_2 = "test.topic.#";// 定義扇形交換機相關的常量// 隊列1名稱public static final String FANOUT_QUEUE_1 = "test.fanout.queue1";// 隊列2名稱public static final String FANOUT_QUEUE_2 = "test.fanout.queue2";// 交換機名稱public static final String FANOUT_EXCHANGE = "test.fanout.exchange";// 1. 直連型交換機隊列/*** 聲明直連型交換機的隊列** @return 隊列對象*/@Beanpublic Queue directQueue() {log.info("創建隊列: " + DIRECT_QUEUE);return new Queue(DIRECT_QUEUE, true);}// 2. 主題型交換機隊列/*** 聲明主題型交換機的第一個隊列** @return 隊列對象*/@Beanpublic Queue topicQueue1() {log.info("創建隊列: " + TOPIC_QUEUE_1);return new Queue(TOPIC_QUEUE_1, true);}/*** 聲明主題型交換機的第二個隊列** @return 隊列對象*/@Beanpublic Queue topicQueue2() {log.info("創建隊列: " + TOPIC_QUEUE_2);return new Queue(TOPIC_QUEUE_2, true);}// 3. 扇形交換機隊列/*** 聲明扇形交換機的第一個隊列** @return 隊列對象*/@Beanpublic Queue fanoutQueue1() {log.info("創建隊列: " + FANOUT_QUEUE_1);return new Queue(FANOUT_QUEUE_1, true);}/*** 聲明扇形交換機的第二個隊列** @return 隊列對象*/@Beanpublic Queue fanoutQueue2() {log.info("創建隊列: " + FANOUT_QUEUE_2);return new Queue(FANOUT_QUEUE_2, true);}// 1. 直連型交換機/*** 聲明直連型交換機** @return 交換機對象*/@Beanpublic DirectExchange directExchange() {log.info("創建交換機: " + DIRECT_EXCHANGE);return new DirectExchange(DIRECT_EXCHANGE, true, false);}// 2. 主題型交換機/*** 聲明主題型交換機** @return 交換機對象*/@Beanpublic TopicExchange topicExchange() {log.info("創建交換機: " + TOPIC_EXCHANGE);return new TopicExchange(TOPIC_EXCHANGE, true, false);}// 3. 扇形交換機/*** 聲明扇形交換機** @return 交換機對象*/@Beanpublic FanoutExchange fanoutExchange() {log.info("創建交換機: " + FANOUT_EXCHANGE);return new FanoutExchange(FANOUT_EXCHANGE, true, false);}// 綁定直連型交換機和隊列/*** 綁定直連型交換機和隊列** @return 綁定對象*/@Beanpublic Binding bindingDirect() {log.info("綁定隊列: " + DIRECT_QUEUE + " 到交換機: " + DIRECT_EXCHANGE + ",路由鍵: " + DIRECT_ROUTING_KEY);return BindingBuilder.bind(directQueue()).to(directExchange()).with(DIRECT_ROUTING_KEY);}// 綁定主題型交換機和隊列/*** 綁定主題型交換機的第一個隊列** @return 綁定對象*/@Beanpublic Binding bindingTopic1() {log.info("綁定隊列: " + TOPIC_QUEUE_1 + " 到交換機: " + TOPIC_EXCHANGE + ",路由鍵: " + TOPIC_ROUTING_KEY_1);return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with(TOPIC_ROUTING_KEY_1);}/*** 綁定主題型交換機的第二個隊列** @return 綁定對象*/@Beanpublic Binding bindingTopic2() {log.info("綁定隊列: " + TOPIC_QUEUE_2 + " 到交換機: " + TOPIC_EXCHANGE + ",路由鍵: " + TOPIC_ROUTING_KEY_2);return BindingBuilder.bind(topicQueue2()).to(topicExchange()).with(TOPIC_ROUTING_KEY_2);}// 綁定扇形交換機和隊列/*** 綁定扇形交換機的第一個隊列** @return 綁定對象*/@Beanpublic Binding bindingFanout1() {log.info("綁定隊列: " + FANOUT_QUEUE_1 + " 到交換機: " + FANOUT_EXCHANGE);return BindingBuilder.bind(fanoutQueue1()).to(fanoutExchange());}/*** 綁定扇形交換機的第二個隊列** @return 綁定對象*/@Beanpublic Binding bindingFanout2() {log.info("綁定隊列: " + FANOUT_QUEUE_2 + " 到交換機: " + FANOUT_EXCHANGE);return BindingBuilder.bind(fanoutQueue2()).to(fanoutExchange());}/*** 創建延遲交換機*/@Beanpublic CustomExchange delayedExchange() {Map<String, Object> args = new HashMap<>();args.put("x-delayed-type", "direct");return new CustomExchange("delayed.exchange","x-delayed-message", true, false, args);}/*** 綁定延遲交換機* @return*/@Beanpublic Binding bindingDelayed() {return BindingBuilder.bind(directQueue()).to(delayedExchange()).with(DIRECT_ROUTING_KEY).noargs();}// 使用JSON序列化消息/*** 配置JSON消息轉換器** @return 消息轉換器對象*/@Beanpublic MessageConverter jsonMessageConverter() {log.info("配置JSON消息轉換器");return new Jackson2JsonMessageConverter();}// 配置RabbitTemplate/*** 配置RabbitTemplate,設置消息轉換器以及消息發送確認和返回回調** @param connectionFactory 連接工廠* @return 配置好的RabbitTemplate對象*/@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(jsonMessageConverter());// 消息發送到交換器后確認回調rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {if (ack) {log.info("消息成功發送到Exchange: " + correlationData);} else {log.error("消息發送到Exchange失敗: " + correlationData);}});// 消息從交換器發送到隊列失敗回調rabbitTemplate.setReturnsCallback(returned -> {log.info("消息從Exchange路由到Queue失敗: " + returned.getMessage());log.info("交換機: " + returned.getExchange());log.info("路由鍵: " + returned.getRoutingKey());log.info("返回碼: " + returned.getReplyCode());log.info("返回信息: " + returned.getReplyText());});return rabbitTemplate;}
}

4、創建消息生產者

package com.lw.mqdemo.mq;import com.lw.mqdemo.config.RabbitMQConfig;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.UUID;/*** RabbitMQ生產者類,用于發送不同類型的交換機消息*/
@Component
public class RabbitMQProducer {/*** 注入RabbitTemplate模板,用于發送消息*/@Autowiredprivate RabbitTemplate rabbitTemplate;/*** 注入MessageConverter轉換器,用于將對象轉換為消息*/@Autowiredprivate MessageConverter messageConverter;/*** 發送直連型交換機消息** @param message 要發送的消息對象*/public void sendDirectMessage(Object message) {CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());rabbitTemplate.convertAndSend(RabbitMQConfig.DIRECT_EXCHANGE,   // 交換機名稱RabbitMQConfig.DIRECT_ROUTING_KEY,   // 路由鍵 用于消息路由message,   // 要發送的消息對象correlationData   //  消息的唯一標識);}/*** 發送主題型交換機消息1** @param message 要發送的消息對象*/public void sendTopicMessage1(Object message) {rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE,   // 交換機名稱RabbitMQConfig.TOPIC_ROUTING_KEY_1, // 路由鍵 用于消息路由message // 要發送的消息對象);}/*** 發送主題型交換機消息2** @param message 要發送的消息對象*/public void sendTopicMessage2(Object message) {rabbitTemplate.convertAndSend(RabbitMQConfig.TOPIC_EXCHANGE,  // 交換機名稱"test.topic.routingkey2.test",  // 路由鍵 用于消息路由message);}/*** 發送扇形交換機消息** @param message 要發送的消息對象*/public void sendFanoutMessage(Object message) {rabbitTemplate.convertAndSend(RabbitMQConfig.FANOUT_EXCHANGE,  //   交換機名稱"", // 扇形交換機不需要路由鍵message);}/*** 發送延遲消息** @param message 要發送的消息對象* @param delayMillis 消息延遲的時間(毫秒)*/public void sendDelayedMessage(Object message, int delayMillis) {MessageProperties props = new MessageProperties();props.setDelay(delayMillis);Message msg = messageConverter.toMessage(message, props);rabbitTemplate.convertAndSend("delayed.exchange", // 關鍵修改點RabbitMQConfig.DIRECT_ROUTING_KEY,msg);}
}

5、創建消息消費者

package com.lw.mqdemo.mq;import com.lw.mqdemo.config.RabbitMQConfig;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;import java.io.IOException;/*** RabbitMQ消費者類* 該類包含了對不同類型隊列(直連型、主題型、扇形)的消息消費方法*/
@Component
@Slf4j
public class RabbitMQConsumer {/*** 直連型隊列消費者* 監聽直連型隊列并處理收到的消息** @param message 消息內容* @param channel 消息通道* @throws IOException 當消息處理失敗時拋出異常*/@RabbitListener(queues = RabbitMQConfig.DIRECT_QUEUE)public void processDirectMessage(Message message, Channel channel) throws IOException {try {// 打印收到的消息內容log.info("直連型隊列收到消息: " + new String(message.getBody()));// 手動ACK確認  如果不確認會消息Unacked狀態channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 處理失敗,拒絕消息channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);e.printStackTrace();}}/*** 主題型隊列1消費者* 監聽主題型隊列1并處理收到的消息** @param message 消息內容* @param channel 消息通道* @param msg 消息對象* @throws IOException 當消息處理失敗時拋出異常*/@RabbitListener(queues = RabbitMQConfig.TOPIC_QUEUE_1)public void processTopicMessage1(String message, Channel channel, Message msg) throws IOException {try {// 打印收到的消息內容log.info("主題型隊列1收到消息: " + message);channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 處理失敗,拒絕消息channel.basicNack(msg.getMessageProperties().getDeliveryTag(), false, true);e.printStackTrace();}}/*** 主題型隊列2消費者* 監聽主題型隊列2并處理收到的消息** @param message 消息內容* @param channel 消息通道* @param msg 消息對象* @throws IOException 當消息處理失敗時拋出異常*/@RabbitListener(queues = RabbitMQConfig.TOPIC_QUEUE_2)public void processTopicMessage2(String message, Channel channel, Message msg) throws IOException {try {// 打印收到的消息內容log.info("主題型隊列2收到消息: " + message);channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 處理失敗,拒絕消息channel.basicNack(msg.getMessageProperties().getDeliveryTag(), false, true);e.printStackTrace();}}/*** 扇形隊列1消費者* 監聽扇形隊列1并處理收到的消息** @param message 消息內容* @param channel 消息通道* @param msg 消息對象* @throws IOException 當消息處理失敗時拋出異1常*/@RabbitListener(queues = RabbitMQConfig.FANOUT_QUEUE_1)public void processFanoutMessage1(String message, Channel channel, Message msg) throws IOException {try {// 打印收到的消息內容log.info("扇形隊列1收到消息: " + message);channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 處理失敗,拒絕消息channel.basicNack(msg.getMessageProperties().getDeliveryTag(), false, true);e.printStackTrace();}}/*** 扇形隊列2消費者* 監聽扇形隊列2并處理收到的消息** @param message 消息內容* @param channel 消息通道* @param msg 消息對象* @throws IOException 當消息處理失敗時拋出異常*/@RabbitListener(queues = RabbitMQConfig.FANOUT_QUEUE_2)public void processFanoutMessage2(String message, Channel channel, Message msg) throws IOException {try {// 打印收到的消息內容log.info("扇形隊列2收到消息: " + message);channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 處理失敗,拒絕消息channel.basicNack(msg.getMessageProperties().getDeliveryTag(), false, true);e.printStackTrace();}}
}

6、創建測試控制器

package com.lw.mqdemo.controller;import com.lw.mqdemo.mq.RabbitMQProducer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** RabitMQ控制器* @author lw*/
@Slf4j
@RestController
@RequestMapping("/rabbitmq")
public class RabbitMQController {//  注入RabbitMQ生產者@Autowiredprivate RabbitMQProducer rabbitMQProducer;/*** 發送直連型消息* @return*/@GetMapping("/direct")public String sendDirectMessage() {log.info("發送直連型消息");rabbitMQProducer.sendDirectMessage("這是一條直連型交換機消息");return "直連型消息發送成功";}/*** 發送主題型消息1* @return*/@GetMapping("/topic1")public String sendTopicMessage1() {log.info("發送主題型消息1");rabbitMQProducer.sendTopicMessage1("這是一條主題型交換機消息1");return "主題型消息1發送成功";}/*** 發送主題型消息2* @return*/@GetMapping("/topic2")public String sendTopicMessage2() {log.info("發送主題型消息2");rabbitMQProducer.sendTopicMessage2("這是一條主題型交換機消息2");return "主題型消息2發送成功";}@GetMapping("/fanout")public String sendFanoutMessage() {log.info("發送扇形消息");rabbitMQProducer.sendFanoutMessage("這是一條扇形交換機消息");return "扇形消息發送成功";}/*** 發送延遲消息* @return*/@GetMapping("/delay")public String sendDelayedMessage() {log.info("發送延遲消息");// 延遲5秒rabbitMQProducer.sendDelayedMessage("這是一條延遲消息", 5000);return "延遲消息發送成功,5秒后消費";}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/85531.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/85531.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/85531.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用Java將PDF轉換成GIF

為什么要將 PDF 文件轉換為 GIF 圖片&#xff1f; PDF 是一種矢量圖像格式&#xff08;因此可以根據指定的尺寸進行渲染&#xff09;&#xff0c;而 GIF 是一種有損的、固定尺寸的位圖文件&#xff0c;像素值固定。因此&#xff0c;將 PDF 轉換為 GIF 文件時&#xff0c;我們需…

Redis之分布式鎖(2)

上一篇文章我們介紹了什么是分布式鎖和分布式鎖的一些基本概念。這篇文章我們來講解一下基于數據庫如何實現分布式鎖。 基于數據庫實現分布式鎖 基于數據庫實現分布式鎖可以分為兩種方式&#xff0c;分別是基于數據庫表和基于數據庫排他鎖。 基于數據庫表 要實現分布式鎖&…

智能檢測護航電池產業:容量設備如何提升效率與安全?

電池容量是衡量其儲能能力的重要指標&#xff0c;直接影響設備續航與使用壽命。電池容量檢測設備通過模擬真實使用場景&#xff0c;精準測量電池的充放電性能&#xff0c;為電池生產、質檢及回收環節提供關鍵數據支持&#xff0c;成為保障電池品質與安全的核心工具。 核心功能…

介紹一款免費MES、開源MES系統、MES源碼

一、系統概述&#xff1a; 萬界星空科技免費MES、開源MES、商業開源MES、市面上最好的開源MES、MES源代碼、適合二開的開源MES。 1.萬界星空開源MES制造執行系統的Java開源版本。 開源mes系統包括系統管理&#xff0c;車間基礎數據管理&#xff0c;計劃管理&#xff0c;物料控制…

構建高性能日志系統:QGroundControl日志模塊深度解析

引言&#xff1a;日志系統的重要性 在無人機地面站系統中&#xff0c;日志記錄是診斷問題、分析性能的關鍵基礎設施。QGroundControl&#xff08;QGC&#xff09;作為領先的開源無人機地面站軟件&#xff0c;其日志系統設計值得深入探討。本文將揭示QGC日志系統的核心技術&…

k8s查看內存占用前十的20個pod服務,不包括job

在 Kubernetes 中&#xff0c;您可以使用 kubectl 命令結合一些工具來查看內存占用前十的 Pod 服務&#xff0c;并排除 Job 類型的 Pod。以下是一個示例命令&#xff0c;您可以在終端中運行&#xff1a; kubectl top pods --all-namespaces --no-headers | grep -v job | sort …

Spring Boot 集成 LangChain4j 示例

文章目錄 概述一、DeepSeek API Key 獲取二、Spring Boot 集成 LangChain4j 示例三、拓展建議 概述 LangChain4j 是 LangChain 在 Java 生態下的實現&#xff0c;它是一個開源庫&#xff0c;幫助你更方便地在 Spring Boot 應用中集成大語言模型&#xff08;如 OpenAI 的 GPT-4…

數據差異的iOS性能調試:設備日志導出和iOS文件管理

在復雜iOS項目中&#xff0c;尤其是集成多個第三方服務、使用混合數據源&#xff08;本地遠程緩存&#xff09;的系統里&#xff0c;“數據不一致”類問題極具迷惑性。一方面&#xff0c;數據看似可用&#xff0c;邏輯層也沒有明顯錯誤&#xff1b;另一方面&#xff0c;用戶層面…

二進制與生活:從數字世界到人生哲理

二進制與生活&#xff1a;從數字世界到人生哲理 最近重溫《少年謝爾頓》&#xff0c;被劇中謝爾頓與二進制對話的場景深深打動。這讓我思考&#xff1a;二進制這個看似冰冷的數字系統&#xff0c;其實與我們的生活有著千絲萬縷的聯系。今天&#xff0c;讓我們一起走進二進制的世…

基于SMB協議的內網存活主機探測技術研究

一、 技術背景 SMB(Server Message Block)協議是Windows環境中廣泛使用的網絡文件共享協議&#xff0c;默認開放于445端口。由于其在Windows系統中的核心地位&#xff0c;SMB協議常被用作內網探測的重要切入點。本文系統介紹多種基于SMB的存活主機探測技術&#xff0c;幫助安全…

IDEA21中文亂碼解決辦法

我改了很多&#xff0c;可能也改了一些沒用的 1.在VM options中添加-Dstdout.encodingUTF-8 -Dstderr.encodingUTF-8 2.IDEA 控制臺輸出設置為 UTF-8 打開 IDEA → File → Settings&#xff08;或 CtrlAltS&#xff09; 搜索 "Encoding" 設置 Project Encoding 和…

時序數據庫概念及IoTDB特性詳解

一、數據庫管理系統概述 數據&#xff0c;如同空氣般普遍存在于我們的數字生活中&#xff0c;每一次點擊手機都可能產生并記錄數據。這些數據被存儲在數據庫中&#xff0c;而數據庫實質上是“數據的集合”。數據庫管理系統&#xff08;DBMS&#xff09;則負責這些“數據容器”…

leetcode:263. 丑數(python3解法,數學相關算法題)

難度&#xff1a;簡單 丑數 就是只包含質因數 2、3 和 5 的 正 整數。 給你一個整數 n &#xff0c;請你判斷 n 是否為 丑數 。如果是&#xff0c;返回 true &#xff1b;否則&#xff0c;返回 false 。 示例 1&#xff1a; 輸入&#xff1a;n 6 輸出&#xff1a;true 解釋&am…

RK3568筆記八十五:LVGL播放AVI視頻

若該文為原創文章,轉載請注明原文出處。 最近有個需求,需要播放視頻,但使用的框架是LVGL顯示,所以了解了下LVGL怎么實現播放視頻。 目前了解到的方法有兩種: 一、使用ffmpeg方式,此方法適用于大部分視頻 二、使用opencv方式,此方法適用于大部分視頻 三、使用woshin…

stm32使用定時器PWM

1、定時器TIM PSC-Prescaler-預分頻器 CNT-Counter-計數器 ARR-Auto Reload Register-自動重裝寄存器 RCR-Repetition Counter Register-重復計數器 1、時鐘來源:晶振提供頻率,時鐘樹這些才提供時鐘 分頻系數 計數 3、實例 上面展示了假設使用外部石英晶振提供32.76…

2.3 Windows Vcpkg+MSVC編譯FFmpeg 4.4.1

一、vcpkg安裝ffmpeg 4.4.1 vcpkg的使用可以參考之前的文章&#xff1a;vcpkg 使用 1.1 查看vcpkg中的ffmpeg版本 查看庫的版本&#xff1a;vcpkg.io 1.2 vcpkg.json文件解析 創建vcpkg.json文件&#xff1a; {"builtin-baseline": "984f9232b2fe0eb94f…

docker -v 之后docker cp報錯

問題 我現在在本地已經可以正確運行這個文本糾錯接口了&#xff0c;使用了-v 掛載&#xff0c;&#xff0c;當我使用docker cp時&#xff0c;報錯了Error response from daemon: unlinkat /app/pycorrector/.git/objects/pack/pack-xxxxxx.pack: device or resource busy&…

10人團隊SolidWorks云桌面服務器怎么連接

在當今數字化設計領域&#xff0c;SolidWorks作為主流的三維CAD軟件&#xff0c;對硬件性能要求較高。 對于10人團隊共享使用場景&#xff0c;云桌面服務器方案能有效解決硬件成本高、協作效率低等問題&#xff0c;這需從硬件選型、網絡架構、云桌面平臺部署、軟件授權管理及用…

從源碼角度了解Elasticsaerch(分布式協調排序、深分頁問題)

引文 Elasticsearch基于Lucene所以很多系統實現都在其中,所以可以先看看Lucene的實現: https://blog.csdn.net/qq_35040959/article/details/147931034 項目組件 不像Kafka這種頂級項目核心性能組件全自己實現,ELK中有很多引用至第三方開放庫; 網絡模型-Netty 網絡模型多重…