RabbitMQ的死信队列和延迟队列
文章目录
- 死信队列
- 如何配置死信队列
- 死信队列的应用场景
- Spring Boot实现RabbitMQ的死信队列
- 延迟队列
- 方案优劣:
- 延迟队列的实现有两种方式:
死信队列
1)“死信”是RabbitMQ中的一种消息机制。
2)消息变成死信,可能是由于以下的原因
● 消息被拒绝
● 消息过期
● 队列达到最大长度
3)死信队列
当消息在一个队列中变成死信(dead message)之后,它能被重新发送到另一个交换机中,这个交换机就是 DLX(Dead-Letter-Exchange ) ,绑定 DLX 的队列就称之为死信队列。
“死信”消息会被RabbitMQ进行特殊处理,如果配置了死信队列信息,那么该消息将会被丢进死信队列中,如果没有配置,则该消息将会被丢弃。
如何配置死信队列
- 配置业务队列,绑定到业务交换机上
- 为业务队列配置死信交换机和路由key
- 为死信交换机配置死信队列
注意:并不是直接声明一个公共的死信队列,然后所以死信消息就自己跑到死信队列里去了。而是为每个需要使用死信的业务队列配置一个死信交换机,这里同一个项目的死信交换机可以共用一个,然后为每个业务队列分配一个单独的路由key。
有了死信交换机和路由key后,接下来,就像配置业务队列一样,配置死信队列,然后绑定在死信交换机上。也就是说,死信队列并不是什么特殊的队列,只不过是绑定在死信交换机上的队列。死信交换机也不是什么特殊的交换机,只不过是用来接受死信的交换机,所以可以为任何类型【Direct、Fanout、Topic】。一般来说,会为每个业务队列分配一个独有的路由key,并对应的配置一个死信队列进行监听,也就是说,一般会为每个重要的业务队列配置一个死信队列。
具体因为队列消息过期而被投递到死信队列的流程:

死信队列其实并没有什么神秘的地方,不过是绑定在死信交换机上的普通队列,而死信交换机也只是一个普通的交换机,不过是用来专门处理死信的交换机。
死信消息的生命周期:
1)业务消息被投入业务队列
2)消费者消费业务队列的消息,由于处理过程中发生异常,于是进行了nck或者reject操作
3)被nck或reject的消息由RabbitMQ投递到死信交换机中
4)死信交换机将消息投入相应的死信队列
5)死信队列的消费者消费死信消息
死信消息是RabbitMQ为我们做的一层保证,其实我们也可以不使用死信队列,而是在消息消费异常时,将消息主动投递到另一个交换机中,当你明白了这些之后,这些Exchange和Queue想怎样配合就能怎么配合。比如从死信队列拉取消息,然后发送邮件、短信、钉钉通知来通知开发人员关注。或者将消息重新投递到一个队列然后设置过期时间,来进行延时消费
死信队列的应用场景
一般用在较为重要的业务队列中,确保未被正确消费的消息不被丢弃,一般发生消费异常可能原因主要有由于消息信息本身存在错误导致处理异常,处理过程中参数校验异常,或者因网络波动导致的查询异常等等,当发生异常时,当然不能每次通过日志来获取原消息,然后让运维帮忙重新投递消息。
通过配置死信队列,可以让未正确处理的消息暂存到另一个队列中,待后续排查清楚问题后,编写相应的处理代码来处理死信消息,这样比手工恢复数据要好太多了。
Spring Boot实现RabbitMQ的死信队列
当您在使用Spring Boot实现RabbitMQ的死信队列时,您需要完成以下步骤:
- 添加Maven依赖
确保您的pom.xml文件中包含以下Maven依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
这将为您的应用程序提供RabbitMQ的基本支持。
2. 配置RabbitMQ连接信息
在application.properties或application.yml文件中添加RabbitMQ的连接信息,包括主机地址、用户名、密码等。
3. 创建RabbitMQConfig类
创建一个配置类,用于定义交换机、队列以及它们之间的绑定关系。在这个类中,您需要定义普通队列、死信队列、死信交换机,并将它们进行绑定。
4. 创建消费者类
创建一个消费者类,使用@RabbitListener注解标记需要监听的死信队列,并在方法上使用@RabbitHandler注解来处理接收到的死信消息。
5. 发送消息到普通队列
在需要发送消息的地方,使用RabbitTemplate发送消息到普通队列中。当消息因为过期或被拒绝接收时,会被标记为死信消息,并根据参数设置转发到死信交换机中,然后路由到死信队列中。
下面是一个简单的示例代码,演示了如何在Spring Boot中实现RabbitMQ的死信队列,并消费死信队列的消息:
// RabbitMQConfig.java
@Configuration
public class RabbitMQConfig {@Beanpublic Queue myQueue() {return QueueBuilder.durable("my_queue").withArgument("x-dead-letter-exchange", "dlx_exchange").withArgument("x-dead-letter-routing-key", "dlq_queue").build();}@Beanpublic Queue dlqQueue() {return QueueBuilder.durable("dlq_queue").build();}@Beanpublic Exchange dlxExchange() {return ExchangeBuilder.directExchange("dlx_exchange").durable(true).build();}@Beanpublic Binding binding(Queue myQueue, Exchange dlxExchange) {return BindingBuilder.bind(myQueue).to(dlxExchange).with("my_queue").noargs();}
}// DeadLetterQueueConsumer.java
@Component
@RabbitListener(queues = "dlq_queue")
public class DeadLetterQueueConsumer {@RabbitHandlerpublic void processDeadLetterMessage(String message) {System.out.println("Received message from dead letter queue: " + message);// 处理接收到的死信消息}
}// RabbitMQService.java
@Service
public class RabbitMQService {@Autowiredprivate RabbitTemplate rabbitTemplate;public void sendMessage() {rabbitTemplate.convertAndSend("my_queue", "Hello, RabbitMQ!");}
}
通过以上步骤,您就可以在Spring Boot项目中实现RabbitMQ的死信队列,并消费死信队列的消息。
延迟队列
延迟队列存储的对象是对应的延迟消息;所谓“延迟消息” 是指当消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到这个消息进行消费。
在RabbitMQ中延迟队列可以通过 过期时间 + 死信队列 来实现;具体如下流程图所示:

RabbitMQ 的基因中没有延时队列这回事,它不能直接指定一个队列类型为延时队列,然后去延时处理,但是经过上面两节的铺垫,我们可以将 TTL+DLX 相结合,这就能组成一个延时队列。
设想一个场景,下完订单之后 15 分钟未付款我们就要将订单关闭,这就是一个很经典的演示消费的场景,如果拿 RabbitMQ 来做,我们就需要结合 TTL+DLX 了。
先把订单消息设置好 15 分钟过期时间,然后过期后队列将消息转发给我们设置好的 DLX-Exchange,DLX-Exchange 再将分发给它绑定的队列,我们的消费者再消费这个队列中的消息,就做到了延时十五分钟消费。
RabbitMQ 有两个特性,一个是 Time-To-Live Extensions,另一个是 Dead Letter Exchanges。
Time-To-Live Extensions
RabbitMQ允许我们为消息或者队列设置TTL(time to live),也就是过期时间。TTL表明了一条消息可在队列中存活的最大时间,单位为毫秒。也就是说,当某条消息被设置了TTL或者当某条消息进入了设置了TTL的队列时,这条消息会在经过TTL秒后 “死亡”,成为Dead Letter。如果既配置了消息的TTL,又配置了队列的TTL,那么较小的那个值会被取用。
Dead Letter Exchanges
在 RabbitMQ 中,一共有三种消息的 “死亡” 形式:
● 消息被拒绝。通过调用 basic.reject 或者 basic.nack 并且设置的 requeue 参数为 false;
● 消息因为设置了TTL而过期;
● 队列达到最大长度。
DLX同一般的 Exchange 没有区别,它能在任何的队列上被指定,实际上就是设置某个队列的属性。当队列中有 DLX 消息时,RabbitMQ就会自动的将 DLX 消息重新发布到设置的 Exchange 中去,进而被路由到另一个队列,publish 可以监听这个队列中消息做相应的处理。
由上简介大家可以看出,RabbitMQ本身是不支持延迟队列的,只是他的特性让勤劳的 中国脱发群体 急中生智(为了完成任务)弄出了这么一套可用的方案。
可用的方案就是:
- 如果有事件需要延迟那么将该事件发送到MQ 队列中,为需要延迟的消息设置一个TTL;
- TTL到期后就会自动进入设置好的DLX,然后由DLX转发到配置好的实际消费队列;
- 消费该队列的延迟消息,处理事件。
方案优劣:
优点:
大品牌组件,用的放心。如果面临大数据量需求可以很容易的横向扩展,同时消息支持持久化,有问题可回滚。
缺点:
- 配置麻烦,额外增加一个死信交换机和一个死信队列的配置;
- RabbitMQ 是一个消息中间件,TTL 和 DLX 只是他的一个特性,将延迟队列绑定在一个功能软件的某一个特性上,可能会有风险。不要杠,当你们组不用 RabbitMQ 的时候迁移很痛苦;
- 消息队列具有先进先出的特点,如果第一个进入队列的消息 A 的延迟是10分钟,第二个进入队列的消息B 的延迟是5分钟,期望的是谁先到 TTL谁先出,但是事实是B已经到期了,而还要等到 A 的延迟10分钟结束A先出之后,B 才能出。所以在设计的时候需要考虑不同延迟的消息要放到不同的队列。另外该问题官方已经给出了插件来支持:插件地址。
延迟队列的实现有两种方式:
通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;
使用 RabbitMQ-delayed-message-exchange 插件实现延迟功能。
针对任务丢失的代价过大,高并发的场景
优点: 支持集群,分布式,高并发场景;
缺点: 引入额外的消息队列,增加项目的部署和维护的复杂度。
场景:为一个委托指定期限,委托到期后,委托关系终止,相关业务权限移交回原拥有者 这里采用的是RabbitMq的死信队列加TTL消息转化为延迟队列的方式(RabbitMq没有延时队列)
①声明一个队列设定其的死信队列
@Configuration
public class MqConfig {public static final String GLOBAL_RABBIT_TEMPLATE = "rabbitTemplateGlobal";public static final String DLX_EXCHANGE_NAME = "dlxExchange";public static final String AUTH_EXCHANGE_NAME = "authExchange";public static final String DLX_QUEUE_NAME = "dlxQueue";public static final String AUTH_QUEUE_NAME = "authQueue";public static final String DLX_AUTH_QUEUE_NAME = "dlxAuthQueue";@Bean@Qualifier(GLOBAL_RABBIT_TEMPLATE)public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);return rabbitTemplate;}@Bean@Qualifier(AUTH_EXCHANGE_NAME)public Exchange authExchange() {return ExchangeBuilder.directExchange (AUTH_EXCHANGE_NAME).durable (true).build ();}/*** 死信交换机* @return*/@Bean@Qualifier(DLX_EXCHANGE_NAME)public Exchange dlxExchange() {return ExchangeBuilder.directExchange (DLX_EXCHANGE_NAME).durable (true).build ();}/*** 记录日志的死信队列* @return*/@Bean@Qualifier(DLX_QUEUE_NAME)public Queue dlxQueue() {// Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)return QueueBuilder.durable (DLX_QUEUE_NAME).build ();}/*** 委托授权专用队列* @return*/@Bean@Qualifier(AUTH_QUEUE_NAME)public Queue authQueue() {return QueueBuilder.durable (AUTH_QUEUE_NAME).withArgument("x-dead-letter-exchange", DLX_EXCHANGE_NAME).withArgument("x-dead-letter-routing-key", "dlx_auth").build ();}/*** 委托授权专用死信队列* @return*/@Bean@Qualifier(DLX_AUTH_QUEUE_NAME)public Queue dlxAuthQueue() {// Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)return QueueBuilder.durable (DLX_AUTH_QUEUE_NAME).withArgument("x-dead-letter-exchange", DLX_EXCHANGE_NAME).withArgument("x-dead-letter-routing-key", "dlx_key").build ();}@Beanpublic Binding bindDlxQueueExchange(@Qualifier(DLX_QUEUE_NAME) Queue dlxQueue, @Qualifier(DLX_EXCHANGE_NAME) Exchange dlxExchange){return BindingBuilder.bind (dlxQueue).to (dlxExchange).with ("dlx_key").noargs ();}/*** 委托授权专用死信队列绑定关系* @param dlxAuthQueue* @param dlxExchange* @return*/@Beanpublic Binding bindDlxAuthQueueExchange(@Qualifier(DLX_AUTH_QUEUE_NAME) Queue dlxAuthQueue, @Qualifier(DLX_EXCHANGE_NAME) Exchange dlxExchange){return BindingBuilder.bind (dlxAuthQueue).to (dlxExchange).with ("dlx_auth").noargs ();}/*** 委托授权专用队列绑定关系* @param authQueue* @param authExchange* @return*/@Beanpublic Binding bindAuthQueueExchange(@Qualifier(AUTH_QUEUE_NAME) Queue authQueue, @Qualifier(AUTH_EXCHANGE_NAME) Exchange authExchange){return BindingBuilder.bind (authQueue).to (authExchange).with ("auth").noargs ();}}②发送含过期时间的消息 向授权交换机,发送路由为"auth"的消息(指定了业务所需的超时时间) =》发向MqConfig.AUTH_QUEUE_NAME 队列
rabbitTemplate.convertAndSend(MqConfig.AUTH_EXCHANGE_NAME, "auth", "类型:END,信息:{id:1,fromUserId:111,toUserId:222,beginData:20201204,endData:20211104}", message -> {/*** MessagePostProcessor:消息后置处理* 为消息设置属性,然后返回消息,相当于包装消息的类*///业务逻辑:过期时间=xxxxString ttl = "5000";//设置消息的过期时间message.getMessageProperties ().setExpiration (ttl);return message;});
复制代码
③超时后队列MqConfig.AUTH_QUEUE_NAME会将消息转发至其配置的死信路由"dlx_auth",监听该死信队列即可消费定时的消息/*** 授权定时处理* @param channel* @param message*/@RabbitListener(queues = MqConfig.DLX_AUTH_QUEUE_NAME)public void dlxAuthQ(Channel channel, Message message) throws IOException {System.out.println ("\n死信原因:" + message.getMessageProperties ().getHeaders ().get ("x-first-death-reason"));//1.判断消息类型:1.BEGIN 2.ENDtry {//2.1 类型为授权到期(END)//2.1.1 修改报件办理人//2.1.2 修改授权状态为0(失效)//2.2 类型为授权开启(BEGIN)//2.2.1 修改授权状态为1(开启)System.out.println (new String(message.getBody (), Charset.forName ("utf8")));channel.basicAck (message.getMessageProperties ().getDeliveryTag (), false);System.out.println ("已处理,授权相关信息修改成功");} catch (Exception e) {//拒签消息channel.basicNack (message.getMessageProperties ().getDeliveryTag (), false, false);System.out.println ("授权相关信息处理失败, 进入死信队列记录日志");}}
相关文章:
RabbitMQ的死信队列和延迟队列
文章目录 死信队列如何配置死信队列死信队列的应用场景Spring Boot实现RabbitMQ的死信队列 延迟队列方案优劣:延迟队列的实现有两种方式: 死信队列 1)“死信”是RabbitMQ中的一种消息机制。 2)消息变成死信,可能是由于…...
PyQt 逻辑与界面分离
将逻辑与界面分离是一种良好的软件设计实践,可以提高代码的可维护性和可扩展性。在使用 pyuic 工具转换 Qt Designer 的 .ui 文件时,你可以通过以下方式实现逻辑与界面的分离: 创建一个单独的 Python 模块,用于编写主窗口的逻辑代…...
opengl播放3d pose 原地舞蹈脚来回飘动
目录 opengl播放3d pose 原地舞蹈脚来回飘动 设置相机视角 opengl播放3d pose 原地舞蹈脚来回飘动 opengl播放3d pose 原地舞蹈时,脚来回飘动,正常状态是脚应该不动的。 经过反复分析实验验证,找到原因是,渲染计算3d坐标时,都要减去一个offset,这个offset是髋关节的坐…...
Linux环境基础开发工具使用篇(三) git 与 gdb
一、版本控制器-git 1.简单理解: ①git既是服务端,又是客户端 ②git会记录版本的变化 ③git是一个去中心化的分布式软件 git/gitee 是基于git仓库搭建的网站,让版本管理可视化 2.git 三板斧提交代码 查看安装的git版本 git--version 命令行提交代…...
mybatis---->tx中weekend类
🙌首先weekend可不是mybatis中的类呦~~🙌 它是来自于mybatis的一个扩展库! 如果你要在springboot中使用,需要引入以下依赖~~ <dependency><groupId>tk.mybatis</groupId><artifactId>mapper-spring-boot…...
Shell echo、printf、test命令
目录 Shell echo命令 打印文本消息 显示变量值 输出特殊字符 输出到文件 追加到文件 Shell printf 命令 打印简单文本 Shell test 命令 文件测试 字符串比较 整数比较 逻辑运算 Shell echo命令 打印文本消息 echo "Hello, World!" 显示变量值 name&q…...
腾讯云主机Ubuntu22.04安装Odoo17
一、安装PostgreSQL16 参见之前的文章 Ubuntu22.04安装PostgreSQL-CSDN博客 二、安装Odoo17 本方案使用的nightly版的odoo,安装的都是最新版odoo wget -O - https://nightly.odoo.com/odoo.key | apt-key add - echo "deb http://nightly.odoo.com/17.0/n…...
conda常用命令详解
Conda 是一个功能强大的包管理器和环境管理器,用于安装、部署和管理软件包和其依赖关系。下面是一些常用的 Conda 命令及其详细解释: 创建环境: conda create --name myenv python3.8可以指定创建环境的目录conda create --prefix /path/to/d…...
Java面试——锁
公平锁: 是指多个线程按照申请锁的顺序来获取锁,有点先来后到的意思。在并发环境中,每个线程在获取锁时会先查看此锁维护的队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会…...
Spring Boot与Netty:构建高性能的网络应用
点击下载《Spring Boot与Netty:构建高性能的网络应用》 1. 前言 本文将详细探讨如何在Spring Boot应用中集成Netty,以构建高性能的网络应用。我们将首先了解Netty的原理和优势,然后介绍如何在Spring Boot项目中集成Netty,包括详…...
ARMv8-AArch64 的异常处理模型详解之异常处理详解(同步异常和异步异常的分析和处理)
这里写目录标题 一,同步异常的分析1.1 同步异常分析-异常链接寄存器ELR1.2 同步异常分析-异常综合寄存器ESR,Exception Syndrome Register1.3 同步异常分析-错误地址寄存器FAR,Fault Address Register 二, 同步异常的处理示例 Synchronous ex…...
Elasticsearch:基于 Langchain 的 Elasticsearch Agent 对文档的搜索
在今天的文章中,我们将重点介绍如何使用 LangChain 提供的基础设施在 Python 中构建 Elasticsearch agent。 该 agent 应允许用户以自然语言询问有关 Elasticsearch 集群中数据的问题。 Elasticsearch 是一个强大的搜索引擎,支持词法和向量搜索。 Elast…...
学习python的第7天,她不再开放她的听歌榜单
我下午登录上小号,打开聊天消息看到了她的回复,我很开心兴奋,可是她不再开放她的听歌榜单了,我感觉得到,我要失恋了。 “因为当年电视上看没有王菲版本的” “行”。 “那你以后还会开放听歌榜单吗?”我…...
多维时序 | Matlab实现CPO-BiTCN-BiGRU冠豪猪优化时间卷积神经网络双向门控循环单元多变量时间序列预测模型
多维时序 | Matlab实现CPO-BiTCN-BiGRU冠豪猪优化时间卷积神经网络双向门控循环单元多变量时间序列预测模型 目录 多维时序 | Matlab实现CPO-BiTCN-BiGRU冠豪猪优化时间卷积神经网络双向门控循环单元多变量时间序列预测模型预测效果基本介绍程序设计参考资料 预测效果 基本介绍…...
低代码与大语言模型的探索实践
低代码系列文章: 可视化拖拽组件库一些技术要点原理分析可视化拖拽组件库一些技术要点原理分析(二)可视化拖拽组件库一些技术要点原理分析(三)可视化拖拽组件库一些技术要点原理分析(四)低代码…...
element导航菜单el-menu添加搜索功能
element导航菜单-侧栏,自带的功能没有搜索或者模糊查询。 找了找资料 找到一个比较可行的,记录一下: //index.vue的代码 <div style"overflow:auto"><el-menu :default-active"$route.path":default-openeds&…...
浅析SpringBoot框架常见未授权访问漏洞
文章目录 前言Swagger未授权访问RESTful API 设计风格swagger-ui 未授权访问swagger 接口批量探测 Springboot Actuator未授权访问数据利用未授权访问防御手段漏洞自动化检测工具 CVE-2022-22947 RCE漏洞原理分析与复现漏洞自动化利用工具 其他常见未授权访问Druid未授权访问漏…...
PostgreSQL内存上下文系统设计概述
PostgreSQL内存上下文系统设计概述 原文:src/backend/utils/mmgr/README 背景 我们在“内存上下文”中进行大部分内存分配,通常是AllocSets由src/backend/utils/mmgr/aset.c实现。在没有大量开销的情况下成功进行内存管理的关键是定义一组具有适当生命周期的有用…...
C++ 网络编程学习二
C 网络编程学习二 asio异步写操作asio异步读操作asio 异步echo服务端asio异步服务器中存在的隐患 asio异步写操作 async_write_some是异步写的函数:传入buffer和回调函数以及参数以后,发送后会调用回调函数。 void Session::WriteToSocketErr(const st…...
SpringMVC 学习(四)之获取请求参数
目录 1 通过 HttpServletRequest 获取请求参数 2 通过控制器方法的形参获取请求参数 3 通过 POJO 获取请求参数(重点) 1 通过 HttpServletRequest 获取请求参数 public String handler1(HttpServletRequest request) <form action"${pageCont…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
