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

Spring Cloud 之RabbitMQ的学习【详细】

服务通信

分布式系统通信两种方式:

  1. 直接远程调用(同步)
  2. 借助第三方间接通信(异步)

同步通讯的问题

Feign就属于同步通讯。存在的如下问题

  • 耦合度高,每次添加新的模块就要修改原有模块的代码
  • 性能下降,调用者需要等待服务者返回的结果,如果调用链过长,则响应的时间越长
  • 资源浪费,在等待的过程中,不会释放CPU与内存资源,在高并发的场景下占用浪费资源过大
  • 级联失败,当调用链中一个服务宕机,那么调用者也会出现问题。

异步调用方案

异步调用常见的实现方式为事件驱动模式

事件驱动模式优点:

  • 服务解耦,添加模块不需要更改其他服务的代码
  • 性能提升,在用户请求的模块可以直接返回结果,不需要等待其他服务执行完毕后再返回结果
  • 服务没有强依赖关系,一个服务宕机不会影响到其他服务
  • 流量削峰

缺点:

  • 依赖了第三方组件,第三方组件需要保证可靠性、安全性、吞吐能力
  • 架构复杂,业务没有明显流程线,不好追踪管理
  • 一致性问题

MQ

MQ:Message Queue消息队列,是消息在传输的过程中保存消息的容器。多用于分布式系统之间进行通信

Kafka适用于数据量大但对数据安全性不高的场景比如说日志的传输

RabbitMQ与RocketMQ适用于对数据安全要求较高的场景,比如说业务之间的传输信息

满足什么条件才可以使用MQ?

  1. 生产者不需要从消费者处获取任何信息
  2. 容许短暂不一致性
  3. 使用MQ的效果收益大于管理MQ成本

RabbitMQ的下载

在虚拟机上启动dokcer服务后拉去rabbitmq镜像

systemctl start docker
docker pull rabbitmq

RabbitMQ的启动

docker run \
-e RABBITMQ_DEFAULT_USER=admin \
-e RABBITMQ_DEFAULT_PASS=admin \
--name mq \
--hostname mql \
-p 15672:15672 \
-p 5672:5672 \
-d \
rabbitmq:latest

命令解释:

-e RABBITMQ_DEFAULT_USER=admin :指定登录账号为admin

-e RABBITMQ_DEFAULT_PASS=admin :指定登录密码为admin

--name mq :容器名为mq

--hostname mq1 主机名为mq1(做集群时使用,不添加也可以)

-p 15672:15672 端口映射

-p 5672:5672

-d 后台允许

rabbitmq:latest

访问15672端口输入密码登录

可能会遇到的问题

1、关闭防火墙后访问端口仍然无法访问15672端口

解决方法:

开启防火墙
systemctl start firewalld
开放端口
firewall-cmd --zone=public --add-port=15672/tcp --permanent
重新加载配置文件
firewall-cmd --reload

2、即使开放了端口15672也无法访问页面

解决方法:

如果是docker拉取的rabbitmq镜像,需要手动进入容器下载rabbitmq的管理插件

进入容器
docker exec -it 容器名 bash
下载rabbitmq的管理插件
rabbitmq-plugins enable rabbitmq_management
修改配置文件
cd  /etc/rabbitmq/conf.d/
echo management_agent.disable_metrics_collector = false > management_agent.disable_metrics_collector.conf
退出镜像
exit
重启rabbitmq
docker restart 容器名

RabbitMQ的结构与概念

RabbitMQ中的几个概念

  • channel:操作MQ的工具
  • exchange:路由消息到队列中
  • queue:缓存消息
  • virtualhost:虚拟主机,是对queue、exchange等资源的逻辑分组

常见消息模型

不使用交换机的

  • 基本消息队列
  • 工作消息队列

使用交换机的

  • Fanout Exchange:广播
  • Direct Exchange:路由
  • Topic Exchange:主题

简单消息队列的实现

只存在三种角色:

  • publisher:消息发布者,将消息发送到队列queue
  • queue:消息队列,负责接受并缓存消息
  • consumer:订阅队列,处理队列中的消息

示例代码:

引入依赖

<dependencies><!--rabbitMQ的Java客户端--><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.16.0</version></dependency>
</dependencies>
/*** 发送消息方*/
public class Producer_Hello {public static void main(String[] args) throws IOException, TimeoutException {//1、创建连接工厂ConnectionFactory connectionFactory = new ConnectionFactory();//2、设置参数connectionFactory.setHost("192.168.116.131");connectionFactory.setPort(5672);//默认也是5672connectionFactory.setVirtualHost("/");//设置虚拟机 默认值是/connectionFactory.setUsername("admin");//默认值是guestconnectionFactory.setPassword("admin");//默认值是guest//3、创建连接ConnectionConnection connection = connectionFactory.newConnection();//4、创建ChannelChannel channel = connection.createChannel();//5、创建队列Queue/*** String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments* 参数* 1.queue:队列名称* 2.durable:是否持久化* 3.exclusive:*      *是否独占。只能有一个消费者监听这队列当*      *Connection关闭时,是否删除队列全* 4.autoDelete:是否自动删除。当没有Consumer时,自动删除掉* 5.arguments:参数。*///如果没有一个交helloWorld的队列,那么会自动创建一个channel.queueDeclare("hello_World",true,false,false,null);//6、发送消息/*** String exchange, String routingKey, BasicProperties props, byte[] body* 1、exchange交换机(简单模式下不会使用交换机,默认使用"")* 2、routingKey:路由名称* 3、props:配置信息* 4、body:发送消息数据*/String body="Hello";channel.basicPublish("","hello_World",null,body.getBytes());//7、释放资源channel.close();connection.close();}
}

首先看到目前没有连接

打断点启动

当Connection connection = connectionFactory.newConnection()运行结束后。查看控制台连接信息

接下来启动消费者

public class Consumer_Hello {public static void main(String[] args) throws Exception {//1、创建连接工厂ConnectionFactory connectionFactory = new ConnectionFactory();//2、设置参数connectionFactory.setHost("192.168.116.131");connectionFactory.setPort(5672);//默认也是5672connectionFactory.setVirtualHost("/");//设置虚拟机 默认值是/connectionFactory.setUsername("admin");//默认值是guestconnectionFactory.setPassword("admin");//默认值是guest//3、创建连接ConnectionConnection connection = connectionFactory.newConnection();//4、创建ChannelChannel channel = connection.createChannel();//5、创建队列Queue/*** String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments* 参数* 1.queue:队列名称* 2.durable:是否持久化,当mq重启之后,还在* 3.exclusive:*      *是否独占。只能有一个消费者监听这队列当*      *Connection关闭时,是否删除队列全* 4.autoDelete:是否自动删除。当没有Consumer时,自动删除掉* 5.arguments:参数。*///如果没有一个交helloWorld的队列,那么会自动创建一个channel.queueDeclare("hello_World",true,false,false,null);/*** String queue, boolean autoAck, Consumer callback* queue:队列名称* autoAck:是否自动确认* callback:回调对象*/Consumer consumer =new DefaultConsumer(channel){/*回调方法,收到消息后,自动执行*/@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("consumerTag:"+consumerTag);System.out.println("envelope:"+envelope.getExchange());System.out.println("properties:"+properties);System.out.println("body:"+new String(body));}};channel.basicConsume("hello_World",true,consumer);//消费者需要监听因此不需要关闭资源}
}

生产者与消费者都需要声明队列是为了避免队列不存在的情况

SpringAMQP的使用

AMQP是用于在应用程序或之间传递业务消息的开放标准。该协议与语言和平台无关,更符合微服务中独立性的要求。而SpringAMQP是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息。包含两部分,其中spring-amqp是基础抽象,spring-rabbit是底层的默认实现

生产者实现

引入依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>

在application.yml配置如下信息

spring:rabbitmq:host: 192.168.116.131port: 5672username: adminpassword: adminvirtual-host: /

编写测试类

@SpringBootTest
@RunWith(SpringRunner.class)
public class test {@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void testSend2SimpleQueue() throws Exception {String queueName ="hello";String message = "hello, spring amqp";rabbitTemplate.convertAndSend(queueName,message);}
}

运行测试观察rabbit控制台

消费者实现

引入依赖和配置相关信息与消费者相同,不同的是,编写一个监听器去监听队列

@Component
public class SpringRabbitListener {@RabbitListener(queues = "hello")public void listenSimpleQueueMessage(String msg){System.out.println("接收到消息:"+msg);}
}

启动引导类观察控制台

Work Queue工作队列

提高消息处理速度, 避免消息的堆积问题

案例实现:

生产者1秒内生产50条消息

    @Testpublic void testWorkQueueSendMessage() throws Exception {String queueName ="hello";String message = "hello, spring amqp__";for (int i = 0; i < 50; i++) {rabbitTemplate.convertAndSend(queueName,message+i);Thread.sleep(20);}}

而消费者代码如下

@Component
public class SpringRabbitListener {@RabbitListener(queues = "hello")public void listenWorkQueueMessage1(String msg) throws InterruptedException {System.out.println("消费者1接收到消息:"+msg);Thread.sleep(30);}@RabbitListener(queues = "hello")public void listenWorkQueueMessage2(String msg) throws InterruptedException {System.out.println("====消费者2接收到消息:"+msg);Thread.sleep(50);}
}

运行结果如下

可以看到每个消费者各处理25条,消费者1处理更快处理结束不会去处理更多的消息而是等待消费者2处理结束。

这种情况是因为Rabbit中存在消息预取的行为,当消息处理前会从Channel中提前拿去一部分消息(类似于轮询平均分配)后再去处理,当我们希望处理更快的设备能够读取更多的消息时,我们可以设置消息预取限制。在application.yml文件中添加如下配置

spring:rabbitmq:host: 192.168.116.131port: 5672username: adminpassword: adminvirtual-host: /listener:simple:prefetch: 1 #每次最多获取一条消息,处理完成后才能获取下一条消息

修改完后再次执行观察控制台

可以看到消费能力更强的处理消息更多。

工作队列模式应用于任务过重或任务过多的场景(比如说发送短信)

发布订阅模式

前两种模式只是将消息发送给一个消费者,而发布订阅模式可以将消息发送给多个消费者。实现方式是加入了exchange(交换机)。exchange只负责路由,不负责存储。路由失败则消息丢失。

Fanout交换机(广播模式)

@Configuration
public class FanoutConfig {//声明交换机@Beanpublic FanoutExchange fanoutExchange(){return new FanoutExchange("fanoutExchange");}//声明队列@Beanpublic Queue queue1(){return new Queue("fanoutQueue1");}@Beanpublic Queue queue2(){return new Queue("fanoutQueue2");}//声明绑定关系@Beanpublic Binding binding1(Queue queue1,FanoutExchange exchange){return BindingBuilder.bind(queue1).to(exchange);}@Beanpublic Binding binding2(Queue queue2,FanoutExchange exchange){return BindingBuilder.bind(queue2).to(exchange);}
}

重启消费者观察Rabbit控制台

编写监听器

@Component
public class SpringRabbitListener {@RabbitListener(queues = "fanoutQueue1")public void listenFanoutQueueMessage1(String msg){System.out.println("从队列queue1中获取到消息:"+msg);}@RabbitListener(queues = "fanoutQueue2")public void listenFanoutQueueMessage2(String msg){System.out.println("从队列queue2中获取到消息:"+msg);}
}

编写生产者测试类

    @Testpublic void testFanoutQueueSendMessage() throws Exception {String exchangeName = "fanoutExchange";String message = "hello, fanout";rabbitTemplate.convertAndSend(exchangeName,"",message);}

启动观察Rabbit控制台

Direct交换机(路由模式)

  1. 每一个Queue都与Exchange设置一个BindingKey
  2. 发布者发送消息时,指定消息的RoutingKey
  3. Exchange将消息路由到BindingKey与消息RoutingKey一致的队列

案例实现

如果和Fanout模式一样去声明绑定关系的话,会比较麻烦,编写代码较多,我们可以采用注解的方式去声明绑定关系。

@Component
public class SpringRabbitListener {@RabbitListener(bindings = @QueueBinding(value = @Queue("directQueue1"),exchange = @Exchange(value = "directExchange",type = ExchangeTypes.DIRECT),key = {"red","blue"}))public void listenDirectQueueMessage1(String msg){System.out.println("从队列queue1中获取到消息:"+msg);}@RabbitListener(bindings = @QueueBinding(value = @Queue("directQueue2"),exchange = @Exchange(value = "directExchange",type = ExchangeTypes.DIRECT),key = {"red","yellow"}))public void listenDirectQueueMessage2(String msg){System.out.println("从队列queue1中获取到消息:"+msg);}
}

运行消费者后观察Rabbit控制台

编写生产者测试类代码

    @Testpublic void testDirectQueueSendMessage() throws Exception {String exchangeName = "directExchange";String message = "hello, direct";rabbitTemplate.convertAndSend(exchangeName, "blue", message);rabbitTemplate.convertAndSend(exchangeName, "red", message + " red");rabbitTemplate.convertAndSend(exchangeName, "yellow", message + " yellow");}

运行观察控制台

TopicExchange(话题模式)

案例实现

@Component
public class SpringRabbitListener {@RabbitListener(bindings = @QueueBinding(value = @Queue("topicQueue1"),exchange = @Exchange(value = "topicExchange",type = ExchangeTypes.TOPIC),key = "china.#"))public void listenTopicQueueMessage1(String msg){System.out.println("从中国话题队列中获取到消息:"+msg);}@RabbitListener(bindings = @QueueBinding(value = @Queue("topicQueue2"),exchange = @Exchange(value = "topicExchange",type = ExchangeTypes.TOPIC),key = "#.news"))public void listenTopicQueueMessage2(String msg){System.out.println("从新闻话题队列中获取到消息:"+msg);}
}

运行观察Rabbit控制台

编写生产者测试类代码

    @Testpublic void testTopicQueueSendMessage() throws Exception {String exchangeName = "topicExchange";String message = "hello, topic";rabbitTemplate.convertAndSend(exchangeName, "china.news", message+" 中国新闻");rabbitTemplate.convertAndSend(exchangeName, "china.#", message + "晴朗");rabbitTemplate.convertAndSend(exchangeName, "#.news", message + "战争");}

运行观察Rabbit控制台

发送三条消息但共有5条消息

消息转换器

在简单消息队列的实现中,我们发送消息发送的是字节数组。但是接收的消息反而是String类型的字符。那是因为。Spring中对消息的处理是由org.springframework.amqp.support.converter.MessageConverter处理默认使用SimpleMessageConverter来实现序列化(基于JDK的ObjectOutputStream实现)

进行一个测试,创建一个object.queue队列,发送一个Map类型的数据

    @Testpublic void testSendObject() throws Exception {Map<String, Object> map = new HashMap<>();map.put("name","zmbwcx");String queueName = "object.queue";rabbitTemplate.convertAndSend(queueName,map);}

观察Rabbit控制台

消息内容被JDK序列化为上图内容,这种序列化方式不安全且占用内存更大。增加了传输成本。

我们可以修改为JSON的序列化方式,具体操作如下

<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId>
</dependency>
@Bean
public MessageConverter jsonMessageConverter(){return new Jackson2JsonMessageConverter();
}

重新发送一条消息,观察Rabbit控制台

生产者与消费者应该使用同一个消息转换器,因此,消费者也应进行相同操作

相关文章:

Spring Cloud 之RabbitMQ的学习【详细】

服务通信 分布式系统通信两种方式&#xff1a; 直接远程调用&#xff08;同步&#xff09;借助第三方间接通信&#xff08;异步&#xff09; 同步通讯的问题 Feign就属于同步通讯。存在的如下问题 耦合度高&#xff0c;每次添加新的模块就要修改原有模块的代码性能下降&am…...

第五章 I/O管理 六、I/O核心子系统

目录 一、核心子系统 1、I/O调度 2、设备保护 二、假脱机技术 1、脱机&#xff1a; 2、假脱机&#xff08;SPOOLing技术&#xff09;&#xff1a; 3、应用&#xff1a; 1.独占式设备&#xff1a; 2.共享设备&#xff1a; 4、共享打印机原理分析 三、总结 一、核心子系…...

winfrom窗体比例缩放

用于控件大小随窗体大小等比例缩放的C#代码。该代码可以在窗体重载中使用&#xff0c;以确保窗体中的控件在窗体大小改变时能够按比例缩放。 SetTag方法&#xff1a;该方法用于设置控件的Tag属性&#xff0c;以存储控件的宽度、高度、左边距、顶边距和字体大小等信息。SetCont…...

宇信科技:强势行业加速融入AIGC,同时做深做细

【科技明说 &#xff5c; 重磅专题】 大家可能没有想到&#xff0c;一向对外低调行事的宇信科技&#xff0c;在AIGC方面2023年就已经训练出了适配金融场景的垂直模型&#xff0c;并应用到了各产品线上&#xff0c;同时结合通用大模型预研了宇信金融系统编程大模型。宇信金融系…...

Google Play上的Android广告软件应用程序积累了200万次安装

大家好&#xff0c;今天我们要聊一聊Google Play上的一个热门话题——Android广告软件应用程序。最近&#xff0c;一些恶意应用程序在Google Play上累积了200万次的安装量&#xff0c;给用户推送了讨厌的广告&#xff0c;同时又隐藏了它们在受感染设备上的存在。 根据Doctor W…...

算法通关村第四关-黄金挑战栈的经典问题

括号匹配问题 描述 : 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有…...

前端开发必备技能!用简单CSS代码绘制三角形,提升用户体验

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、前…...

想翻译pdf文档,试了几个工具对比:有阿里(完全免费,快,好用,质量高,不用注册登录)道最好(有限免费) 百度(有限免费)和谷歌完全免费(网不好)

文档翻释作为基础设施&#xff0c;工作必备。 阿里 &#xff08;完全免费&#xff0c;快&#xff0c;好用&#xff0c;质量高&#xff0c;不用注册登录&#xff0c;无广告&#xff09;我给满分 https://translate.alibaba.com/#core-translation 先选好语言。 Google(完全免…...

c# .net linux ImageSharp+FastDFS+Base64上传图片,压缩图片大小,图像处理dcoker中使用也可以

.net 以前是用System.Drawing来处理图片&#xff0c;但是在dcoker 、linux上用不了 微软官方推荐用 1、SkiaSharp 如果项目运行到docker里&#xff0c;需要NUGET安装SkiaSharp.NativeAssets.Linux.NoDependencies 注意&#xff1a;如果你同时引用SkiaSharp.NativeAssets.Li…...

Flutter FittedBox

&#x1f525; 英文单词FittedBox &#x1f525; Fitted 通过有道翻译如下 &#xff1a; Box 通过有道翻译如下 &#xff1a; 对 FittedBox 的理解 我们可以将 FittedBox 理解为合适的盒子&#xff0c;将其它布局放到FittedBox这样一个盒子中&#xff0c;从而实现 盒子里面的…...

亚信科技:发挥自我优势深入AIGC,并购整合高瞻远瞩致力未来路

【科技明说 &#xff5c; 重磅专题】 亚信科技在IT提供商领域中是一个低调的前行者&#xff0c;在全球通信及大型企业市场中扮演着重要的角色。对于近年来如火如荼AI方面的投入与研究&#xff0c;亚信科技是否也很重视呢&#xff1f; 事实上&#xff0c;是肯定的回答。 在我看…...

【设计模式】第17节:行为型模式之“解释器模式”

一、简介 解释器模式为某个语言定义它的语法&#xff08;或者叫文法&#xff09;表示&#xff0c;并定义一个解释器用来处理这个语法。 二、适用场景 领域特定语言复杂输入解释可扩展的语言结构 三、UML类图 四、案例 对输入的特定格式的打印语句进行解析并执行。 packag…...

各传输介质详细知识点

一.百兆网传输介质 快速以太网(802.3u) 100Base-T2 电缆&#xff1a;2对3类UTP 最大段长&#xff1a;100m 特性阻抗&#xff1a;100 100Base-T4 电缆&#xff1a;4对3类UTP 最大段长&#xff1a;100m 特点&#xff1a;8B/6T&#xff0c;NRZ编码 特性阻抗&#xff1a;1…...

历史随想随记

古往今来所有的王侯将相如不都成为人们茶余饭后的笑谈&#xff0c;一个人无论多么厉害&#xff0c;多么聪明&#xff0c;多么奸诈&#xff0c;多么有权势&#xff0c;他们都逃不出一个结局——死亡&#xff0c;我觉得这是人生最大的悲哀。看历史看的多了&#xff0c;就会发现这…...

ClickHouse Java多个参数的UDF编写

一、环境版本 环境版本docker clickhouse22.3.10.22 docker pull clickhouse/clickhouse-server:22.3.10.22二、XML配置 2.1 配置文件 # 创建udf配置文件 vim /etc/clickhouse-server/demo_function.xml<functions><function><type>executable</type&…...

RPA除了和OCR、NLP技术结合,还能和什么技术结合?

鉴于业内现在也经常把RPA称为数字员工&#xff0c;就虚拟一个人的形象来解答吧。 首先是头部&#xff0c;实现人的“听看说想”能力&#xff1a; 听&#xff1a;ASR&#xff08;语音识别技术&#xff09;&#xff0c;主要用于听取和理解语音输入&#xff0c;让RPA能处理语音数…...

AssertionError: Torch not compiled with CUDA enabled

Pytorch和CUDA版本不兼容&#xff0c;运行python后&#xff08;终端输入python回车&#xff09;用以下代码测试 import torch print(torch.__version__) print(torch.cuda.is_available())返回False则说明目前的pytorch版本无法使用显卡&#xff0c;如下图所示 接着重装合适版…...

【Ubuntu 系统使用进入,自动进入base虚拟环境解决最全】

项目场景&#xff1a; 在Ubuntu上安装完anaconda后&#xff0c;发现每次打开终端后都会自动进入到base的虚拟环境中去&#xff0c;虽然在这些环境下使用问题不大&#xff0c;但一些软件的安装在虚拟环境下有影响。每次使用conda deactivate退出也很麻烦。 问题描述 安装玩之…...

C++项目——云备份-⑨-服务端与客户端功能联调

文章目录 专栏导读1.服务端源代码2.客户端源代码3.浏览器访问测试//listshow 4.上传文件测试5.文件下载测试 专栏导读 &#x1f338;作者简介&#xff1a;花想云 &#xff0c;在读本科生一枚&#xff0c;C/C领域新星创作者&#xff0c;新星计划导师&#xff0c;阿里云专家博主&…...

Linux两条服务器实现相互免密登录

1.准备两台虚拟机&#xff0c;一台充当服务器端&#xff08;server&#xff09;&#xff0c;一台充当客户端&#xff08;client&#xff09; 服务器端&#xff08;server&#xff09;&#xff1a;192.168.75.139 客户端&#xff08;client&#xff09;&#xff1a;192.168.75…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...