当前位置: 首页 > news >正文

RabbitMQ 可靠性投递

文章目录

  • 前言
  • 一、RabbitMQ自带机制
    • 1、生产者发送消息
      • 注意
      • 1.1、事务(Transactions)
      • 1.2、发布确认(Publisher Confirms)
        • 1.2.1、同步
        • 1.2.2、异步
    • 2、消息路由机制
      • 2.1、使用备份交换机(Alternate Exchanges)
      • 2.2、启用消息的确认回调(Return Callbacks)
      • 2.3、配置死信交换机(Dead Letter Exchanges)
    • 3、消息存储持久化机制
      • 3.1、队列持久化(Durable Queue)
      • 3.2、消息持久化(Persistent Message)
      • 3.3、集群部署
    • 4、消费者消费消息
  • 二、业务保证
    • 1、最终一致性
    • 2、监控和告警


前言

RabbitMQ 是一个流行的消息队列系统,用于在分布式系统中传递消息。其中一个重要特性是其可靠性投递(Reliable Message Delivery),保证消息在队列和消费者之间可靠的传递和处理。


一、RabbitMQ自带机制

RabbitMQ 的架构图
在这里插入图片描述

从架构图中,我们可以发现,消息投递的关键步骤在于如下四点
在这里插入图片描述

  • 1.生产者发送消息
  • 2.消息路由机制
  • 3.消息存储持久化机制
  • 4.消费者消费消息

接下来我们一步一步进行分析

1、生产者发送消息

当网络中断或者节点不存在等,均有可能导致生产者发送消息失败,对于失败,可以通过如下机制进行处理

  • 事务(Transactions)
  • 发布确认(Publisher Confirms)

事务(Transactions)和发布确认(Publisher Confirms)是两种确保消息持久性和可靠性的方法。

注意

事务提供了一种全有或全无的机制,但通常不建议在生产环境中使用,因为它们会显著降低性能。发布确认则提供了更轻量级的解决方案,具有更高的性能和灵活性。

1.1、事务(Transactions)

事务的工作原理

  • 事务机制确保一组消息的发送要么全部成功,要么全部失败。如果提交事务失败,所有消息都会回滚,确保数据一致性。

使用方法

  • 启动事务:在信道上启动事务模式。
  • 提交事务:成功时提交所有消息。
  • 回滚事务:发生错误时回滚所有消息。

示例

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;public class RabbitMQTransaction {private final static String QUEUE_NAME = "transaction_queue";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);try {// 启动事务模式channel.txSelect();for (int i = 0; i < 10; i++) {String message = "Message " + i;channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("Sent: " + message);}// 提交事务channel.txCommit();System.out.println("Transaction committed");} catch (Exception e) {System.out.println("Transaction failed: " + e.getMessage());// 回滚事务channel.txRollback();System.out.println("Transaction rolled back");}}}
}

1.2、发布确认(Publisher Confirms)

1.2.1、同步

相较于事务,发布确认(Publisher Confirms)是更为推荐的方式,因为它可以提供类似的可靠性并且具有更好的性能表现:

  • 发布:使用 channel.confirmSelect() 启用发布确认模式。
  • 回调:在发布消息后调用 channel.waitForConfirmsOrDie 方法等待确认,或捕获 Exception 进行错误处理。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConfirmCallback;public class RabbitMQPublishConfirm {private final static String QUEUE_NAME = "confirm_queue";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection();Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);// 启用发布确认模式channel.confirmSelect();// 发布消息for (int i = 0; i < 10; i++) {String message = "Message " + i;channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("Sent: " + message);}// 确认所有发布的消息// 批量确认结果, ACK 如果是 Multiple=True, 代表 ACK 里面的 Delivery-Tag 之前的消息都被确认了// 比如 5 条消息可能只收到 1 个 ACK, 也可能收到 2 个(抓包才看得到)// 直到所有信息都发布, 只要有一个未被 Broker 确认就会 Exceptionchannel.waitForConfirmsOrDie(5000);System.out.println("All messages confirmed");} catch (Exception e) {System.err.println("Message publishing failed: " + e.getMessage());}}
}
1.2.2、异步

异步确认模式(Asynchronous Confirmations)在发布确认模式的基础上提供了更高效和灵活的消息确认机制。相比于同步发布确认,异步模式允许发布者继续发送消息而不必等待每条消息的确认。这种模式更适合高吞吐量的生产环境。以下是实现异步确认模式的详细步骤和示例代码:

  • 建立连接和信道:与RabbitMQ服务器建立连接并创建信道。
  • 启用发布确认模式:使用 channel.confirmSelect() 方法。
  • 设置确认回调(Confirms Callback):定义消息确认和未确认的回调方法。
    • ConfirmCallback: 用于确认成功的回调。
    • ConfirmListener: 用于设定成功和失败的回调。
  • 发送消息:发布者继续发送消息,不需要等待确认。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ConfirmCallback;public class AsyncConfirmPublisher {private static final String QUEUE_NAME = "async_confirm_queue";public static void main(String[] args) throws Exception {ConnectionFactory factory = new ConnectionFactory();factory.setHost("localhost");try (Connection connection = factory.newConnection(); Channel channel = connection.createChannel()) {channel.queueDeclare(QUEUE_NAME, true, false, false, null);// 启用发布确认模式channel.confirmSelect();// 设置确认和未确认的回调处理事件ConfirmCallback ackCallback = (deliveryTag, multiple) -> {System.out.println("Message ACKed with delivery tag: " + deliveryTag + ", multiple: " + multiple);};ConfirmCallback nackCallback = (deliveryTag, multiple) -> {System.err.println("Message NACKed with delivery tag: " + deliveryTag + ", multiple: " + multiple);};channel.addConfirmListener(ackCallback, nackCallback);// 发布消息for (int i = 0; i < 10; i++) {String message = "Message " + i;channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8"));System.out.println("Sent: " + message);}}}
}

2、消息路由机制

当 routingKey 错误,或者队列不存在的时候,就会出现无法路由,导致消息投递失败,解决方案

  • 使用备份交换机(Alternate Exchanges):如果消息无法路由到指定的交换机,RabbitMQ 可以将消息路由到一个备用交换机。
  • 启用消息的确认回调(Return Callbacks):当消息无法路由到任何队列时,可以使用回调函数捕获并处理这些未被路由的消息。
  • 配置死信交换机(Dead Letter Exchanges):当消息在队列中无法被消费或出现错误时,可将消息转发到死信交换机进行之后处理。

2.1、使用备份交换机(Alternate Exchanges)

备份交换机可以防止消息丢失,如果消息无法路由到主交换机,会被备份交换机存储。

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String PRIMARY_EXCHANGE = "primary_exchange";private static final String PRIMARY_QUEUE = "primary_queue";private static final String ALTERNATE_EXCHANGE = "alternate_exchange";private static final String ALTERNATE_QUEUE = "alternate_queue";@Beanpublic ConnectionFactory connectionFactory() {// Configuration connection factory, assuming default settingsreturn new CachingConnectionFactory("localhost");}@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnCallback(returnCallback);return rabbitTemplate;}@Beanpublic DirectExchange primaryExchange() {return ExchangeBuilder.directExchange(PRIMARY_EXCHANGE).durable(true).alternate(ALTERNATE_EXCHANGE).build();}@Beanpublic DirectExchange alternateExchange() {return new DirectExchange(ALTERNATE_EXCHANGE);}@Beanpublic Queue primaryQueue() {return QueueBuilder.durable(PRIMARY_QUEUE).build();}@Beanpublic Queue alternateQueue() {return new Queue(ALTERNATE_QUEUE);}@Beanpublic Binding bindingPrimary() {return BindingBuilder.bind(primaryQueue()).to(primaryExchange()).with("primary_key");}@Beanpublic Binding bindingAlternate() {return BindingBuilder.bind(alternateQueue()).to(alternateExchange()).with("");}private final RabbitTemplate.ReturnCallback returnCallback = (message, replyCode, replyText,exchange, routingKey) -> {// Handle undeliverable messageSystem.err.printf("Message returned: %s, code: %d, text: %s, exchange: %s, routing key: %s%n",new String(message.getBody()), replyCode, replyText, exchange, routingKey);};
}

2.2、启用消息的确认回调(Return Callbacks)

启用消息的确认回调,当消息无法路由到任何队列时,可以使用回调函数捕获并处理这些未被路由的消息。

import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String PRIMARY_EXCHANGE = "primary_exchange";private static final String PRIMARY_QUEUE = "primary_queue";@Beanpublic ConnectionFactory connectionFactory() {return new CachingConnectionFactory("localhost");}@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {// 错误处理逻辑System.err.printf("Message returned: %s, code: %d, text: %s, exchange: %s, routing key: %s%n",new String(message.getBody()), replyCode, replyText, exchange, routingKey);});return rabbitTemplate;}@Beanpublic DirectExchange primaryExchange() {return ExchangeBuilder.directExchange(PRIMARY_EXCHANGE).durable(true).build();}@Beanpublic Queue primaryQueue() {return QueueBuilder.durable(PRIMARY_QUEUE).build();}@Beanpublic Binding bindingPrimary() {return BindingBuilder.bind(primaryQueue()).to(primaryExchange()).with("primary_key");}
}

2.3、配置死信交换机(Dead Letter Exchanges)

消息在队列中无法被消费或出现错误时,可将其转发到死信交换机进行特定处理。

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String PRIMARY_EXCHANGE = "primary_exchange";private static final String PRIMARY_QUEUE = "primary_queue";private static final String DLX_EXCHANGE = "dlx_exchange";private static final String DLX_QUEUE = "dlx_queue";@Beanpublic ConnectionFactory connectionFactory() {return new CachingConnectionFactory("localhost");}@Beanpublic RabbitTemplate rabbitTemplate() {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());rabbitTemplate.setMandatory(true);rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {// 错误处理逻辑System.err.printf("Message returned: %s, code: %d, text: %s, exchange: %s, routing key: %s%n",new String(message.getBody()), replyCode, replyText, exchange, routingKey);});return rabbitTemplate;}@Beanpublic DirectExchange primaryExchange() {return new DirectExchange(PRIMARY_EXCHANGE);}@Beanpublic DirectExchange dlxExchange() {return new DirectExchange(DLX_EXCHANGE);}@Beanpublic Queue primaryQueue() {return QueueBuilder.durable(PRIMARY_QUEUE).withArgument("x-dead-letter-exchange", DLX_EXCHANGE).build();}@Beanpublic Queue dlxQueue() {return QueueBuilder.durable(DLX_QUEUE).build();}@Beanpublic Binding bindingPrimary() {return BindingBuilder.bind(primaryQueue()).to(primaryExchange()).with("primary_key");}@Beanpublic Binding bindingDLX() {return BindingBuilder.bind(dlxQueue()).to(dlxExchange()).with("#");}
}

3、消息存储持久化机制

如果消息没有持久化,当RabbitMQ服务重启、节点故障等情况下就会丢失消息,解决方案

3.1、队列持久化(Durable Queue)

创建队列时将其设置为持久化

channel.queueDeclare("queue_name", durable=True)

3.2、消息持久化(Persistent Message)

发送消息时将其标记为持久化

channel.basicPublish(exchange='', routingKey='queue_name', body=msg, properties=pika.BasicProperties(delivery_mode=2,))

3.3、集群部署

保证节点的高可用

4、消费者消费消息

在使用 RabbitMQ 作为消息队列系统时,消费者确认机制(Consumer Acknowledge)对于确保消息可靠消费非常重要。当消费者从队列中接收到消息时,必须明确确认消息已被成功处理。这种机制不仅防止消息丢失,还避免了消息重复消费的问题。
RabbitMQ 提供了两种主要的消息确认机制:

  • 手动确认(Manual Acknowledgement):消费者显式地向 RabbitMQ 发送确认消息,表明消息已被成功处理。
  • 自动确认(Automatic Acknowledgement):RabbitMQ 在消息被发送给消费者后立即认为消息已经成功处理,无需等待显式确认。(默认)
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {private static final String EXCHANGE_NAME = "direct_exchange";private static final String QUEUE_NAME = "example_queue";@Beanpublic DirectExchange directExchange() {return new DirectExchange(EXCHANGE_NAME);}@Beanpublic Queue queue() {return new Queue(QUEUE_NAME, true);}@Beanpublic Binding binding(Queue queue, DirectExchange exchange) {return BindingBuilder.bind(queue).to(exchange).with("routing_key");}@Beanpublic SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,MessageListenerAdapter listenerAdapter) {SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.setQueueNames(QUEUE_NAME);container.setMessageListener(listenerAdapter);// 自动确认 AcknowledgeMode.AUTO// 手动确认 AcknowledgeMode.MANUALcontainer.setAcknowledgeMode(org.springframework.amqp.core.AcknowledgeMode.MANUAL); return container;}@Beanpublic MessageListenerAdapter listenerAdapter(Consumer consumer) {return new MessageListenerAdapter(consumer, "consumeMessage");}
}

如果是手动确认,消费者处理消息的时候实现手动确认机制:

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;@Component
public class Consumer implements ChannelAwareMessageListener {@Overridepublic void onMessage(Message message, Channel channel) throws Exception {try {// 处理消息逻辑String body = new String(message.getBody());System.out.println("Received message: " + body);// 手动确认消息channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {// 消息处理失败,拒绝消息并重新入队channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);System.err.println("Failed to process message: " + e.getMessage());}}
}

二、业务保证

1、最终一致性

  • 消息持久化处理:在发出消息之前,将消息存储到持久化存储设备,如数据库。 并使用消息状态进行追踪,每个状态表示消息的处理进度。
  • 补偿机制:根据超时和失败记录进行消息补偿。
    • 怎么触发重发(定时任务)
    • 多久触发一次(参考业务属性)
    • 触发多少次(参考业务属性)
  • 幂等性:确保消费者在处理消息时是幂等的,即多次处理不会导致副作用。

通过以上的方案结合,保证消息的最终一致性

2、监控和告警

建立监控系统,及时发现和处理异常情况,然后及时作出相应,增加客户的良好体验
例如:
使用 Prometheus 和 Grafana 对消息队列和数据库进行监控,及时发现并告警异常情况。
也可以结合业务属性,自己创建一套简单的监控系统。

相关文章:

RabbitMQ 可靠性投递

文章目录 前言一、RabbitMQ自带机制1、生产者发送消息注意1.1、事务&#xff08;Transactions&#xff09;1.2、发布确认&#xff08;Publisher Confirms&#xff09;1.2.1、同步1.2.2、异步 2、消息路由机制2.1、使用备份交换机&#xff08;Alternate Exchanges&#xff09;2.…...

Java常见的技术场景面试题

一、单点登录这块怎么实现的&#xff1f; 单点登录概述 单点登录&#xff1a;Single Sign On&#xff08;简称SSO&#xff09;,只需要登录一次&#xff0c;就可以访问所有信任的应用系统 在以前的时候&#xff0c;一般我们就单系统&#xff0c;所有的功能都在同一个系统上。…...

使用 Postman 进行 API 测试:从入门到精通

使用 Postman 进行 API 测试&#xff1a;从入门到精通 使用 Postman 进行 API 测试&#xff1a;从入门到精通一、什么是 API 测试&#xff1f;二、Postman 简介三、环境搭建四、API 测试流程1. 收集 API 文档2. 发送基本请求示例&#xff1a;发送 GET 请求示例代码&#xff08;…...

用python实现进度条

前言 在Python中&#xff0c;可以使用多种方式实现进度条。以下是几种常见的进度条格式的实现方法&#xff1a; 1. 使用 tqdm 库 tqdm 是一个非常流行的库&#xff0c;可以轻松地在循环中显示进度条。 from tqdm import tqdm import time# 示例&#xff1a;简单的进度条 fo…...

android 自定义通话录音

在 Android 开发中&#xff0c;实现通话录音功能通常涉及到对系统通话的拦截和录音。由于通话录音涉及到用户隐私和安全性&#xff0c;Android 系统对此有严格的限制和要求。在 Android 10&#xff08;API 级别 29&#xff09;及以上版本中&#xff0c;直接访问通话录音功能变得…...

WebSocket——环境搭建与多环境配置

一、前言&#xff1a;为什么要使用多环境配置&#xff1f; 在开发过程中&#xff0c;我们通常会遇到多个不同的环境&#xff0c;比如开发环境&#xff08;Dev&#xff09;、测试环境&#xff08;Test&#xff09;、生产环境&#xff08;Prod&#xff09;等。每个环境的配置和需…...

【自动化办公】批量图片PDF自定义指定多个区域识别重命名,批量识别铁路货物运单区域内容改名,基于WPF和飞桨ocr深度学习模型的解决方案

项目背景介绍 铁路货运企业需要对物流单进行长期存档&#xff0c;以便后续查询和审计。不同的物流单可能包含不同的关键信息&#xff0c;通过自定义指定多个区域进行识别重命名&#xff0c;可以使存档的图片文件名具有统一的规范和明确的含义。比如&#xff0c;将包含货物运单…...

在线教程丨YOLO系列10年更新11个版本,最新模型在目标检测多项任务中达SOTA

YOLO (You Only Look Once) 是计算机视觉领域中最具影响力的实时目标检测算法之一&#xff0c;以其高精度与高效性深受业界青睐&#xff0c;广泛应用于自动驾驶、安防监控、医疗影像等领域。 该模型最早于 2015 年由华盛顿大学研究生 Joseph Redmon 发布&#xff0c;开创了将目…...

c++可变参数详解

目录 引言 库的基本功能 va_start 宏: va_arg 宏 va_end 宏 va_copy 宏 使用 处理可变参数代码 C11可变参数模板 基本概念 sizeof... 运算符 包扩展 引言 在C编程中&#xff0c;处理不确定数量的参数是一个常见的需求。为了支持这种需求&#xff0c;C标准库提供了 &…...

Ubuntu安装VMware17

安装 下载本文的附件&#xff0c;之后执行 sudo chmod x VMware-Workstation-Full-17.5.2-23775571.x86_64.bundle sudo ./VMware-Workstation-Full-17.5.2-23775571.x86_64.bundle安装注意事项&#xff1a; 跳过账户登录的办法&#xff1a;断开网络 可能出现的问题以及解决…...

在Debian 12上安装VNC服务器

不知道什么标题 可以看到这个文章是通过豆包从国外网站copy的&#xff0c;先这样写着好了&#xff0c;具体的我有时间再补充&#xff0c;基本内容都在这里了。 在Debian 12上安装VNC服务器 简介 VNC&#xff08;Virtual Network Computing&#xff0c;虚拟网络计算&#xf…...

设计模式Python版 外观模式

文章目录 前言一、外观模式二、外观模式示例三、抽象外观类四、抽象外观类示例 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&am…...

Selenium 浏览器操作与使用技巧——详细解析(Java版)

目录 一、浏览器及窗口操作 二、键盘与鼠标操作 三、勾选复选框 四、多层框架/窗口定位 五、操作下拉框 六、上传文件操作 七、处理弹窗与 alert 八、处理动态元素 九、使用 Selenium 进行网站监控 前言 Selenium 是一款非常强大的 Web 自动化测试工具&#xff0c;能够…...

论文解读:《基于TinyML毫米波雷达的座舱检测、定位与分类》

摘要 本文提出了一种实时的座舱检测、定位和分类解决方案&#xff0c;采用毫米波&#xff08;mmWave&#xff09;雷达系统芯片&#xff08;SoC&#xff09;&#xff0c;CapterahCAL60S344-AE&#xff0c;支持微型机器学习&#xff08;TinyML&#xff09;。提出了波束距离-多普勒…...

e2studio开发RA2E1(5)----GPIO输入检测

e2studio开发RA2E1.5--GPIO输入检测 概述视频教学样品申请硬件准备参考程序源码下载新建工程工程模板保存工程路径芯片配置工程模板选择时钟设置GPIO口配置按键口配置按键口&Led配置R_IOPORT_PortRead()函数原型R_IOPORT_PinRead()函数原型代码 概述 本篇文章主要介绍如何…...

数据结构:队列篇

图均为手绘,代码基于vs2022实现 系列文章目录 数据结构初探: 顺序表 数据结构初探:链表之单链表篇 数据结构初探:链表之双向链表篇 链表特别篇:链表经典算法问题 数据结构:栈篇 文章目录 系列文章目录前言一.队列的概念和结构1.1概念一、动态内存管理优势二、操作效率与安全性…...

idea中git的简单使用

提交&#xff0c;推送直接合并 合到哪个分支就到先切到哪个分支...

Java中的object类

1.Object类是什么&#xff1f; &#x1f7ea;Object 是 Java 类库中的一个特殊类&#xff0c;也是所有类的父类(超类),位于类继承层次结构的顶端。也就是说&#xff0c;Java 允许把任何类型的对象赋给 Object 类型的变量。 &#x1f7e6;Java里面除了Object类&#xff0c;所有的…...

html2canvas绘制页面并生成图像 下载

1. 简介 html2canvas是一个开源的JavaScript库&#xff0c;它允许开发者在用户的浏览器中直接将HTML元素渲染为画布&#xff08;Canvas&#xff09;&#xff0c;并生成图像。以下是对html2canvas的详细介绍&#xff1a; 2. 主要功能 html2canvas的主要功能是将网页中的HTML元…...

Certum OV企业型通配符SSL

随着网络攻击手段的不断演变&#xff0c;仅仅依靠HTTP协议已无法满足现代企业对数据安全的需求。SSL证书&#xff0c;特别是经过严格验证的组织验证型SSL证书&#xff0c;成为了保护网站数据传输安全、提升用户信任度的标配。 一、Certum OV企业型通配符SSL概述 Certum&#…...

2024年Web前端最新Java进阶(五十五)-Java Lambda表达式入门_eclipse lambda(1),面试必备

对象篇 模块化编程-自研模块加载器 开源分享&#xff1a;【大厂前端面试题解析核心总结学习笔记真实项目实战最新讲解视频】 Arrays.sort(players, sortByName); // 1.3 也可以采用如下形式: Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2))); ??其…...

JVM 四虚拟机栈

虚拟机栈出现的背景 由于跨平台性的设计&#xff0c;Java的指令都是根据栈来设计的。不同平台CPU架构不同&#xff0c;所以不能设计为基于寄存器的。优点是跨平台&#xff0c;指令集小&#xff0c;编译器容易实现&#xff0c;缺点是性能下降&#xff0c;实现同样的功能需要更多…...

V103开发笔记1-20250113

2025-01-13 一、应用方向分析 应用项目&#xff1a; PCBFLY无人机项目&#xff08;包括飞控和手持遥控器&#xff09;&#xff1b; 分析移植项目&#xff0c;应用外设资源包括&#xff1a; GPIO, PWM,USART,GPIO模拟I2C/SPI, ADC,DMA,USB等&#xff1b; 二、移植项目的基本…...

Page Assist - 本地Deepseek模型 Web UI 的安装和使用

Page Assist Page Assist是一个开源的Chrome扩展程序&#xff0c;为本地AI模型提供一个直观的交互界面。通过它可以在任何网页上打开侧边栏或Web UI&#xff0c;与自己的AI模型进行对话&#xff0c;获取智能辅助。这种设计不仅方便了用户随时调用AI的能力&#xff0c;还保护了…...

Cookie及Session---笔记

目录 Cookiecookie简介cookiesession的认证方式tpshop完整登录实现-cookie Sessionsession简介session自动管理cookietpshop完整登录实现-sessioncookie和session的区别获取响应结果指定内容 Cookie cookie简介 工程师针对HTTP协议是无连接无状态特性所设计的一种技术&#x…...

【Block总结】DASI,多维特征融合

论文信息 HCF-Net&#xff08;Hierarchical Context Fusion Network&#xff09;是一种新提出的深度学习模型&#xff0c;专门用于红外小目标检测。该论文于2024年3月16日发布&#xff0c;作者包括Shibiao Xu、ShuChen Zheng等&#xff0c;主要研究机构为北京邮电大学。该模型…...

LabVIEW的智能电源远程监控系统开发

在工业自动化与测试领域&#xff0c;电源设备的精准控制与远程管理是保障系统稳定运行的核心需求。传统电源管理依赖本地手动操作&#xff0c;存在响应滞后、参数调节效率低、无法实时监控等问题。通过集成工业物联网&#xff08;IIoT&#xff09;技术&#xff0c;实现电源设备…...

4.PPT:日月潭景点介绍【18】

目录 NO1、2、3、4​ NO5、6、7、8 ​ ​NO9、10、11、12 ​ 表居中或者水平/垂直居中单元格内容居中或者水平/垂直居中 NO1、2、3、4 新建一个空白演示文稿&#xff0c;命名为“PPT.pptx”&#xff08;“.pptx”为扩展名&#xff09;新建幻灯片 开始→版式“PPT_素材.doc…...

《迪拜AI展:探寻中东人工智能发展的璀璨新篇》

迪拜&#xff1a;AI 浪潮下的闪耀明珠 迪拜&#xff0c;这座位于阿拉伯半岛东部、波斯湾东南岸的城市&#xff0c;犹如一颗璀璨的明珠&#xff0c;在中东地区散发着独特的魅力。它是阿拉伯联合酋长国的第二大城市&#xff0c;也是迪拜酋长国的首府 &#xff0c;凭借优越的地理位…...

axios如何利用promise无痛刷新token

目录 需求 需求解析 实现思路 方法一&#xff1a; 方法二&#xff1a; 两种方法对比 实现 封装axios基本骨架 instance.interceptors.response.use拦截实现 问题和优化 如何防止多次刷新token 同时发起两个或以上的请求时&#xff0c;其他接口如何重试 最后完整代…...

R语言 | 使用 ComplexHeatmap 绘制热图,分区并给对角线分区加黑边框

目的&#xff1a;画热图&#xff0c;分区&#xff0c;给对角线分区添加黑色边框 建议直接看0和4。 0. 准备数据 # 安装并加载必要的包 #install.packages("ComplexHeatmap") # 如果尚未安装 library(ComplexHeatmap)# 使用 iris 数据集 #data(iris)# 选择数值列&a…...

TensorFlow 简单的二分类神经网络的训练和应用流程

展示了一个简单的二分类神经网络的训练和应用流程。主要步骤包括&#xff1a; 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与部署 加载和应用已训练的模型 1. 数据准备与预处理 在本例中&#xff0c;数据准备是通过两个 Numpy 数…...

蓝桥杯备考:模拟算法之字符串展开

P1098 [NOIP 2007 提高组] 字符串的展开 - 洛谷 | 计算机科学教育新生态 #include <iostream> #include <cctype> #include <algorithm> using namespace std; int p1,p2,p3; string s,ret; void add(char left,char right) {string tmp;for(char ch left1;…...

[创业之路-282]:《产品开发管理-方法.流程.工具 》-1- 优秀研发体系的特征、IPD关注的4个关键要素、IPD体系的7个特点

目录 一、优秀研发体系的特征 二、IPD关注的4个关键要素 1. 组织管理 2. 市场管理 3. 流程管理 4. 产品管理 三、IPD体系的7个特点 1、产品开发是投资行为&#xff1a; 2、基于市场的产品研发&#xff1a; 3、平台化开发&#xff0c;大平台&#xff0c;小产品&#x…...

Node.js 与 PostgreSQL 集成:深入 pg 模块的应用与实践

title: Node.js 与 PostgreSQL 集成:深入 pg 模块的应用与实践 date: 2025/2/5 updated: 2025/2/5 author: cmdragon excerpt: 随着 JavaScript 在服务器端编程中的兴起,Node.js 已成为构建高性能网络应用程序的重要平台。PostgreSQL 则以其强大的特性以及对复杂数据结构的…...

【Uniapp-Vue3】从uniCloud中获取数据

需要先获取数据库对象&#xff1a; let db uniCloud.database(); 获取数据库中数据的方法&#xff1a; db.collection("数据表名称").get(); 所以就可以得到下面的这个模板&#xff1a; let 函数名 async () > { let res await db.collection("数据表名称…...

LeetCode 0090.子集 II:二进制枚举 / 回溯

【LetMeFly】90.子集 II&#xff1a;二进制枚举 / 回溯 力扣题目链接&#xff1a;https://leetcode.cn/problems/subsets-ii/ 给你一个整数数组 nums &#xff0c;其中可能包含重复元素&#xff0c;请你返回该数组所有可能的 子集&#xff08;幂集&#xff09;。 解集 不能 …...

Pytest+selenium UI自动化测试实战实例

今天来说说pytest吧&#xff0c;经过几周的时间学习&#xff0c;有收获也有疑惑&#xff0c;总之最后还是搞个小项目出来证明自己的努力不没有白费。 环境准备 1 确保您已经安装了python3.x 2 配置python3pycharmselenium2开发环境 3 安装pytest库pip install p…...

黑马点评 - 商铺类型缓存练习题(Redis List实现)

首先明确返回值是一个 List<ShopType> 类型那么我们修改此函数并在 TypeService 中声明 queryTypeList 方法&#xff0c;并在其实现类中实现此方法 GetMapping("list")public Result queryTypeList() {return typeService.queryTypeList();}实现此方法首先需要…...

C++ 创建和配置dll与lib库

C简明教程&#xff08;13&#xff09;创建和配置dll与lib库_怎样生成lib库和dll库-CSDN博客 C 动态库与静态库详解 一、为什么要引入库的概念 在 C 编程中&#xff0c;随着项目规模的不断扩大&#xff0c;代码量也会急剧增加。如果将所有代码都写在一个源文件中&#xff0c;…...

深度剖析 Veo2 工具:解锁 AI 视频创作新境界

在当下这个 AI 技术日新月异的时代,各种 AI 工具如雨后春笋般涌现,让人目不暇接。今天,我就来给大家好好说道说道谷歌旗下的 Veo2,这可是一款在 AI 视频创作领域相当有分量的工具。好多朋友都在问,Veo2 到底厉害在哪?好不好上手?能在哪些地方派上用场?别着急,今天我就…...

LabVIEW自定义测量参数怎么设置?

以下通过一个温度采集案例&#xff0c;说明在 LabVIEW 中设置自定义测量参数的具体方法&#xff1a; 案例背景 ​ 假设使用 NI USB-6009 数据采集卡 和 热电偶传感器 监测温度&#xff0c;需自定义以下参数&#xff1a; 采样率&#xff1a;1 kHz 输入量程&#xff1a;0~10 V&a…...

JVM执行流程与架构(对应不同版本JDK)

直接上图&#xff08;对应JDK8以及以后的HotSpot&#xff09; 这里主要区分说明一下 方法区于 字符串常量池 的位置更迭&#xff1a; 方法区 JDK7 以及之前的版本将方法区存放在堆区域中的 永久代空间&#xff0c;堆的大小由虚拟机参数来控制。 JDK8 以及之后的版本将方法…...

数据治理项目为什么沦为了PPT工程?

数据治理项目为什么沦为了PPT工程&#xff1f; 数据治理项目为什么沦为PPT工程数据治理项目面临的深层挑战数据治理项目的破局之道 "这个项目明明做了快一年了&#xff0c;怎么感觉还在原地踏步&#xff1f;"数据治理小张最近很烦恼。 整天泡在会议室里&#xff0c;写…...

module ‘matplotlib.cm‘ has no attribute ‘get_cmap‘

目录 解决方法1&#xff1a; 解决方法2&#xff0c;新版api改了&#xff1a; module matplotlib.cm has no attribute get_cmap 报错代码&#xff1a; cmap matplotlib.cm.get_cmap(Oranges) 解决方法1&#xff1a; pip install matplotlib3.7.3 解决方法2&#xff0c;新版…...

HTML5 教程之标签(3)

HTML5 <center> 标签 (已废弃) 定义和用法 <center> 标签对其包围的文本进行水平居中处理。HTML5不支持使用<center>标签&#xff0c;因此有关该标签的更多信息&#xff0c;请参考“HTML <center>标签”部分&#xff01; 示例: <center>这个…...

告别传统办公软件,这款编辑器让你事半功倍!

文章目录 1 界面的多样性2 性能优化3 文档编辑器的新功能4 外部文本支持5 体验感想 ONLYOFFICE最近发布了文档8.2版本&#xff0c;带来了众多新特性和性能改进。作为一名用户和开发者&#xff0c;我对这些更新进行了深入的体验&#xff0c;感受到了不少亮点。 新版本特别强调了…...

AI协助探索AI新构型自动化创新的技术实现

一、AI自进化架构的核心范式 1. 元代码生成与模块化重构 - 代码级自编程&#xff1a;基于神经架构搜索的强化学习框架&#xff0c;AI可通过生成元代码模板&#xff08;框架的抽象层定义、神经元结点-网络拓扑态的编码抽象定义&#xff09;自动组合功能模块。例如&#xff0…...

全能型免费内网穿透工具,全面支持macOS、Windows、Linux及Docker系统

1. 登陆官网网址并注册帐号 ngrok | API Gateway, Kubernetes Networking Secure Tunnels 2 下载并安装工具 3. 启动工具 在命令行执行 ngrok http http://localhost:8080 其中端口可换成用户自己想要穿透的端口 4. 获取穿透地址 命令执行后会出现如下画面&#xff0c;红…...

Web - CSS3浮动定位与背景样式

概述 这篇文章主要介绍了 CSS3 中的浮动定位、背景样式、变形效果等内容。包括 BFC 规范与创建方法、浮动的功能与使用要点、定位的多种方式及特点、边框与圆角的设置、背景的颜色、图片等属性、多种变形效果及 3D 旋转等&#xff0c;还提到了浏览器私有前缀。 BFC规范与浏览…...