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

rabbitmq高级特性(2)TTL、死信/延迟队列、事务与消息分发

目录

1.TTL

1.1.设置消息过期时间

1.2.设置队列过期时间

2.死信队列

2.1.介绍

2.2.演示

3.延迟队列

3.1.模拟实现延迟队列

3.2.延迟队列插件

4.事务与消息分发

4.1.事务 

4.2.消息分发


1.TTL

所谓的ttl,就是过期时间。对于rabbitmq,可以设置队列和消息的过期时间

1.1.设置消息过期时间

(1)相关的交换机和队列

//ttl
@Bean("ttlQueue")
public Queue ttlQueue() {return QueueBuilder.durable(Constant.TTL_QUEUE).build();
}@Bean("ttlDirectExchange")
public DirectExchange ttlDirectExchange() {return ExchangeBuilder.directExchange(Constant.TTL_EXCHANGE).build();
}@Bean("ttlBinding")
public Binding ttlBinding(@Qualifier("ttlQueue") Queue queue,@Qualifier("ttlDirectExchange") Exchange exchange ) {return BindingBuilder.bind(queue).to(exchange).with("ttl").noargs();
}

(2)生产者 -- 生产消息的时候设置ttl

给消息设置过期时间,也就是设置消息对象的属性

第一种写法:

    //ttl@RequestMapping("/ttl")public String ttl() {MessagePostProcessor postProcessor = new MessagePostProcessor() {@Overridepublic Message postProcessMessage(Message message) throws AmqpException {message.getMessageProperties().setExpiration("10000");//设置10秒后过期return message;}};rabbitTemplate.convertAndSend(Constant.TTL_EXCHANGE,"ttl","a ttl test",postProcessor);return "ttl";}

第二种写法:

//ttl
@RequestMapping("/ttl")
public String ttl() {rabbitTemplate.convertAndSend(Constant.TTL_EXCHANGE,"ttl","a ttl test",message -> {message.getMessageProperties().setExpiration("10000");//设置10秒后过期return message;});return "ttl";
}

(3)效果展示

消息在10s后就会自动删除 (本人承诺没有做任何的处理)

(4)设置消息ttl注意事项

 设置消息TTL,即时消息过期,也不会马上从队列中删除,而是在即将投递到消费者之前才会进行判定。如果每次都要扫描整个队列就会很低效。

给A消息设置30s过期,B消息设置10s过期,先将消息A存入队列再存B消息,此时B消息30s后才会被删除。

以上的两条消息是同时消失。

1.2.设置队列过期时间

给队列设置TTL,指的是队列中的消息在TTL后就会被删除,而非队列被删除。

(1)设置交换机和队列

代码给队列设置ttl,在创建队列中调用 ttl() 方法即可

//队列ttl
@Bean("ttlQueue2")
public Queue ttlQueue2() {return QueueBuilder.durable(Constant.TTL_QUEUE2).ttl(20 * 1000).build();//队列中的消息20s后被删除
}@Bean("ttlDirectExchange2")
public DirectExchange ttlDirectExchange2() {return ExchangeBuilder.directExchange(Constant.TTL_EXCHANGE).build();
}@Bean("ttlBinding2")
public Binding ttlBinding2(@Qualifier("ttlQueue") Queue queue,@Qualifier("ttlDirectExchange") Exchange exchange ) {return BindingBuilder.bind(queue).to(exchange).with("ttl2").noargs();
}

(2)生产者与效果

@RequestMapping("/ttl2")
public String ttl2() {rabbitTemplate.convertAndSend(Constant.TTL_EXCHANGE,"ttl2","a ttl2");return "ttl2";
}

给队列设置ttl,在web界面中就会有改效果出现。


如果把设置有ttl的消息发送到设置有ttl的队列中,那么过期时间取值小的一个。

2.死信队列

  • 所谓死信,就是因为种种原因无法被消费的消息。
  • 所以死信队列,就是用来存放死信的队列。
  • 死信到达死信队列的交换机称为DLX(Dead Letter Exchange)
2.1.介绍

(1)死信队列的图解

正常队列中的消息因为一些原因就会变成死信,然后经过一个特定的路由交换,最后到达一个指定的死信队列中,然后再投递给消费者。

(2)消息称为死信的原因

  • 消息被拒绝,且设置了无法入队
  • 消息过期
  • 队列达到最大长度
2.2.演示

要演示死信队列的情况,就需要有两种队列和两种交换机。

(1)声明交换机和队列

@Configuration
public class DlConfig {//正常的交换机和队列@Bean("normalQueue")public Queue normalQueue() {return QueueBuilder.durable(Constant.NORMAL_QUEUE).deadLetterExchange(Constant.DL_EXCHANGE)//绑定死信交换机.deadLetterRoutingKey("dlx")//死信交换机的路由规则.ttl(10000)//10秒后消息过期.maxLength(10L)//队列最大长度为10.build();}@Bean("normalExchange")public DirectExchange normalExchange() {return ExchangeBuilder.directExchange(Constant.NORMAL_EXCHANGE).build();}@Bean("normalBinding")public Binding normalBinding(@Qualifier("normalExchange") DirectExchange normalExchange, @Qualifier("normalQueue")Queue normalQueue) {return BindingBuilder.bind(normalQueue).to(normalExchange).with("normal");}//死信交换机和队列@Bean("dlxQueue")public Queue dlxQueue() {return QueueBuilder.durable(Constant.DL_QUEUE).build();}@Bean("dlxExchange")public DirectExchange dlxExchange() {return ExchangeBuilder.directExchange(Constant.DL_EXCHANGE).build();}@Bean("dlxBinding")public Binding dlxBinding(@Qualifier("dlxExchange") DirectExchange dlxExchange, @Qualifier("dlxQueue")Queue dlxQueue) {return BindingBuilder.bind(dlxQueue).to(dlxExchange).with("dlx");}}

上面我们知道了消息称为死信的条件,其中消息过期和超过队列最大长度可以在声明队列时实现。所以,有如下的代码改进

//正常的交换机和队列
@Bean("normalQueue")
public Queue normalQueue() {return QueueBuilder.durable(Constant.NORMAL_QUEUE).deadLetterExchange(Constant.DL_EXCHANGE)//绑定死信交换机.deadLetterRoutingKey("dlx")//死信交换机的路由规则.ttl(10000)//10秒后消息过期.maxLength(10L)//队列最大长度为10.build();
}

对于消息被拒,我们在消费者部分进行修改就好。

(2)生产者和消费者

生产者:可以选择模拟超出队列最大长度的情况

//dlx死信队列
@RequestMapping("/dlx")
public String dlx() {int maxLen = 12;for(int i=0;i<maxLen;i++) {rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE,"normal","normal and dlx");}return "normal";
}

消费者:

@Component
public class DlListener {//监听正常队列,模拟拒绝消息//@RabbitListener(queues = Constant.NORMAL_QUEUE)public void normalListener() {System.out.println();}//监听死信队列@RabbitListener(queues = Constant.DL_QUEUE)public void dlxListener(Message message) {System.out.println("死信队列:"+ new String(message.getBody()));}}

队列就变成了这样子: 

(3)过期消息变成死信

(4)其他情况

比如拒绝消息和长度超过最大队列长度

3.延迟队列

延迟队列,指消息发送到队列后,消费者并不能马上拿到消息,而是等待指定的时间后才能消息该消息。

应用场景:

(1)智能家居:比如通过手机下达命令控制家里的家居,达到一定时间段就自动开启。

(2)日常管理:预定一个会议,在会议开始前15分钟就会通知参加人员

比如,我们经常使用的手机闹钟,就是类似于延迟队列的效果。

3.1.模拟实现延迟队列

对于原生的rabbitmq,并没有实现延迟队列的功能,但是我们可以通过TTL+死信队列来模拟实现。

(1)如何模拟实现

消费者需要订阅死信队列,生产者把延迟的消息放入正常队列中,当消息过期就会自动进入死信队列,消费者进而可以拿到消息。

对于TTL,我们是设置消息的TTL,也可以设置队列的过期时间。

(2)模拟实现

死信队列:

@Configuration
public class DlConfig {//正常的交换机和队列@Bean("normalQueue")public Queue normalQueue() {return QueueBuilder.durable(Constant.NORMAL_QUEUE).deadLetterExchange(Constant.DL_EXCHANGE)//绑定死信交换机.deadLetterRoutingKey("dlx")//死信交换机的路由规则.build();}@Bean("normalExchange")public DirectExchange normalExchange() {return ExchangeBuilder.directExchange(Constant.NORMAL_EXCHANGE).build();}@Bean("normalBinding")public Binding normalBinding(@Qualifier("normalExchange") DirectExchange normalExchange, @Qualifier("normalQueue")Queue normalQueue) {return BindingBuilder.bind(normalQueue).to(normalExchange).with("normal");}//死信交换机和队列@Bean("dlxQueue")public Queue dlxQueue() {return QueueBuilder.durable(Constant.DL_QUEUE).build();}@Bean("dlxExchange")public DirectExchange dlxExchange() {return ExchangeBuilder.directExchange(Constant.DL_EXCHANGE).build();}@Bean("dlxBinding")public Binding dlxBinding(@Qualifier("dlxExchange") DirectExchange dlxExchange, @Qualifier("dlxQueue")Queue dlxQueue) {return BindingBuilder.bind(dlxQueue).to(dlxExchange).with("dlx");}}

生产者:生产者在生产消息的时候加上过期时间,也就是TTL

@RequestMapping("/delay")
public String delay() {rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE,"normal","这是一条延迟消息",message -> {message.getMessageProperties().setExpiration("10000");//设置10秒后过期return message;});System.out.println("消息发送时间:"+new Date());return "delay";
}

消费者:消费者订阅死信队列

  //监听死信队列@RabbitListener(queues = Constant.DL_QUEUE)public void dlxListener(Message message) {System.out.println("消费时间: "+new Date() +",死信队列:"+ new String(message.getBody()));}

演示结果:

结果恰好是10秒后。

(3)存在的缺陷

前面我们知道,当多个携带TTL的消息进入队列中,并且前面消息的TTL大于后面的;那么就会出现,只有前面的消息过期,后面的消息才会跟着过期,这就是TTL+私信队列存在的问题。

所以我们使用一个插件,使用插件带来的延迟队列进行操作。

3.2.延迟队列插件

(1)下载插件并启用

下载地址:这个页面如果点不开,可以使用加速软件加速

Releases · rabbitmq/rabbitmq-delayed-message-exchange · GitHub

找到.ez文件:点击就会下载插件文件

确定安装目录:

像ubunto的就使用这两个目录的其中一个即可:

将文件复制到目录下:没有目录就创建

找到目录

安装插件前:

安装插件:直接将文件拖拽进来即可

安装插件后:多出来的插件

启动插件:

最后在rabbitmq客户端查看交换机类型

这就说明延迟插件启动成功,后续使用该交换机即可。

(2)定义交换机和队列


@Configuration
public class DelayConfig {@Bean("delayQueue")public Queue delayQueue() {return QueueBuilder.durable(Constant.DELAY_QUEUE).build();}@Bean("delayExchange")public Exchange delayExchange() {return ExchangeBuilder.directExchange(Constant.DELAY_EXCHANGE).delayed().build();}@Bean("delayBinding")public Binding delayBinding(@Qualifier("delayQueue") Queue delayQueue,@Qualifier("delayExchange") Exchange delayExchange) {return BindingBuilder.bind(delayQueue).to(delayExchange).with("delay").noargs();}}

生产者:

@RequestMapping("/delay2")
public String delay2() {rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE,"normal","这是一条延迟消息",message -> {message.getMessageProperties().setExpiration("10000");//设置10秒后过期return message;});System.out.println("消息发送时间:"+new Date());return "delay";
}

消费者:

@Component
public class DelayListener {@RabbitListener(queues = Constant.DELAY_QUEUE)public void delayListener() {System.out.println("消息时间:"+new Date());}}

(3)演示

使用延迟插件就不会出现像上述TTL+死信队列的问题

如果需要关闭插件,执行下面的命令即可:

rabbitmq delayed message exchange

4.事务与消息分发

4.1.事务 

 事务,就是保证发送消息和接收消息是原子性的,要么全部成功,要么全部失败

(1)配置事务管理器

这里就是需要对AMQP客户端进行设置属性

//3.返回事务
@Bean("transRabbitTemplate")
public RabbitTemplate transRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setChannelTransacted(true);//true为开启事务return rabbitTemplate;
}@Beanpublic RabbitTransactionManager transactionManager(CachingConnectionFactory connectionFactory){return new RabbitTransactionManager(connectionFactory);//事务管理器}

后续使用该对象就可以完成事务的操作

(2)准备队列和交换机

这里使用系统默认的交换机即可

   //事务@Bean("transQueue")public Queue transQueue() {return QueueBuilder.durable(Constant.TRANS_QUEUE).build();}

(3)消费者

    @RequestMapping("/trans")public String trans() {rabbitTemplate.convertAndSend("",Constant.TRANS_QUEUE,"第一条消息");System.out.println("异常前");int a=9/0;//模拟发送异常rabbitTemplate.convertAndSend("",Constant.TRANS_QUEUE,"第二条消息");return "trans";}

上面的消费者是没有使用事物的

(4)没有采取事务

这里指的是既没有开启事务,也没有在方法上加上@Transactional注解

运行结果:

异常前成功发送消息,异常后的消息没有进行发送成功。

(5)使用事务

    @Transactional@RequestMapping("/trans")public String trans() {transRabbitTemplate.convertAndSend("",Constant.TRANS_QUEUE,"第一条消息");System.out.println("异常前");int a=9/0;//模拟发送异常transRabbitTemplate.convertAndSend("",Constant.TRANS_QUEUE,"第二条消息");return "trans";}

这个时候发送了异常,队列中也是一条消息都没有的。

(6)事务小结

要完成一个事务的操作,这三个操作都不能少

配置对象和事务管理器:

@Bean("transRabbitTemplate")
public RabbitTemplate transRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setChannelTransacted(true);return rabbitTemplate;
}@Bean
public RabbitTransactionManager rabbitTransactionManager(ConnectionFactory connectionFactory) {return new RabbitTransactionManager(connectionFactory);
}

加上@Transactional注解:

@Transactional
@RequestMapping("/trans")
public String trans() {transRabbitTemplate.convertAndSend("",Constant.TRANS_QUEUE,"第一条消息");//int a=9/0;//模拟发送异常transRabbitTemplate.convertAndSend("",Constant.TRANS_QUEUE,"第二条消息");return "trans";
}

还有一个注意事项,使用事务,最好把消息发送确认模式关闭

4.2.消息分发

(1)定义

多个消费者订阅同一个队列时,队列会轮询给消费者分发消息,每个消费者平均每分钟拿到的消息数目是一样的,这种情况看似挺好的,但是容易出现问题。

当每个消费者的消费能力不一样时,消费速度慢的,消息就会积压;而消费速度快的消费者,就会空闲,进而影响整体的吞吐量。

所以就有了消息分发,按照一定的规则,平均每分钟给不同的消费者分发不同数量的消息。

对于消息分发,有两个应用场景 -- 限流和非公平分发

(2)限流

消费者每次只能拿到一定数量的消息,只有消费并且确认后,才能继续拿到消息。所以需要配置成手动确认模式和限流参数

1)配置

2)相应代码

交换机和队列:

@Configuration
public class QosConfig {@Bean("qosQueue")public Queue qosQueue() {return QueueBuilder.durable(Constant.QOS_QUEUE).build();}@Bean("qosExchange")public Exchange qosExchange() {return ExchangeBuilder.directExchange(Constant.QOS_EXCHANGE).delayed().build();}@Bean("qosBinding")public Binding qosBinding(@Qualifier("qosQueue") Queue delayQueue, @Qualifier("qosExchange") Exchange delayExchange) {return BindingBuilder.bind(delayQueue).to(delayExchange).with("qos").noargs();}}

生产者:

@RequestMapping("/qos")
public String Qos() {for(int i=0;i<20;i++) {rabbitTemplate.convertAndSend(Constant.QOS_EXCHANGE,"qos","a qos test"+i);}return "qos";
}

消费者:

@Component
public class QosListener {@RabbitListener(queues = Constant.QOS_QUEUE)public void qosListener(Message message, Channel channel) throws IOException {long deliveryTag = message.getMessageProperties().getDeliveryTag();try {System.out.println("消费:"+new String(message.getBody()));//channel.basicAck(deliveryTag, false); //不进行消息确认}catch (Exception e){channel.basicNack(deliveryTag, false, false);}}
}

3)演示

一下子往队列中发送20条消息,但是消费者一下子只能拿到5条消息

但是没有确认,就只有五条消息,也拿不到后续的消息。

(3)负载均衡

模拟实现负载均衡,可以把限流参数修改成1,消费确认完成一条消息才能继续拿。

后续代码跟上述是差不多了

相关文章:

rabbitmq高级特性(2)TTL、死信/延迟队列、事务与消息分发

目录 1.TTL 1.1.设置消息过期时间 1.2.设置队列过期时间 2.死信队列 2.1.介绍 2.2.演示 3.延迟队列 3.1.模拟实现延迟队列 3.2.延迟队列插件 4.事务与消息分发 4.1.事务 4.2.消息分发 1.TTL 所谓的ttl&#xff0c;就是过期时间。对于rabbitmq&#xff0c;可以设置…...

了解一下,RN中怎么加载 threejs的

在React Native&#xff08;RN&#xff09;中加载和使用Three.js&#xff0c;一个流行的3D图形库&#xff0c;通常需要一些额外的步骤&#xff0c;因为Three.js主要是为Web浏览器设计的&#xff0c;而React Native则使用原生的渲染引擎。不过&#xff0c;有一些方法可以在React…...

笔记整理—linux驱动开发部分(1)驱动梗概

驱动可以分为广义上的和狭义上的驱动。广义上的驱动是用于操作硬件的代码&#xff0c;而狭义上的驱动为基于内核系统之上让硬件去被操作的逻辑方法。 linux体系架构&#xff1a; 1.分层思想 &#xff1a;在OS中间还会有许多层。 : 2.驱动的上面是系统调用&#xff08;API&…...

金融领域中的敏感性分析和期权价值计算相关的操作

代码主要进行了金融领域中的敏感性分析和期权价值计算相关的操作。首先通过一系列方程求解S3和S2的值,然后基于这些值以及给定的参数计算一些中间变量(a1、a2、a3、b1、b2、b3),最后利用多元正态分布函数(mvncdf)和一元正态分布函数(normcdf)计算期权价值C、净现值(NP…...

GraphQL系列 - 第1讲 GraphQL语法入门

目录 一、介绍GraphQL二、GraphQL基本使用方法三、Schema 定义语言 (SDL)3.1 类型定义1&#xff09;对象类型2&#xff09;标量类型3&#xff09;枚举类型4&#xff09;输入类型5&#xff09;列表类型6&#xff09;非空类型7&#xff09;接口类型8&#xff09;联合类型 3.2 查询…...

015:地理信息系统开发平台ArcGIS Engine10.2与ArcGIS SDK for the Microsoft .NET Framework安装教程

摘要&#xff1a;本文详细介绍地理信息系统开发平台ArcGIS Engine10.2与ArcGIS SDK for the Microsoft .NET Framework的安装流程。 一、软件介绍 ArcGIS Engine 10.2是由Esri公司开发的一款强大的GIS&#xff08;地理信息系统&#xff09;开发平台。该软件基于ArcGIS 10.2 fo…...

Android——显式/隐式Intent

概述 在Android中&#xff0c;Intent是各个组件之间信息通信的桥梁&#xff0c;它用于Android各组件的通信。 Intent 的组成部分 一、显式 Intent 第一种方式 Intent intent new Intent(this, ActFinishActivity.class);startActivity(intent);第二种方式 Intent intent …...

【鸿蒙HarmonyOS实战:通过华为应用市场上架测试版App实现HBuilder X打包的UniApp项目的app转hap教程(邀请码)方式教程详解】

鸿蒙HarmonyOS实战&#xff1a;通过华为应用市场上架测试版App实现HBuilder X打包的UniApp项目的app转hap教程&#xff08;邀请码&#xff09;方式详解 在使用uniapp打包的鸿蒙项目的过程中&#xff0c;由于生成的是app文件&#xff0c;而hdc传给鸿蒙HarmonyOS系统需要的是hap文…...

一篇文章入门傅里叶变换

文章目录 傅里叶变换欧拉公式傅里叶变换绕圈记录法质心记录法傅里叶变换公式第一步&#xff1a;旋转的表示第二步&#xff1a;缠绕的表示第三步&#xff1a;质心的表示最终步&#xff1a;整理积分限和系数 参考文献 傅里叶变换 在学习傅里叶变换之前&#xff0c;我们先来了解一…...

基于python的语音识别与蓝牙通信的温控系统

基于python的语音识别与蓝牙通信的温控系统毕设项目 大家好&#xff0c;我是陈辰学长&#xff0c;一名在 Java 圈辛勤劳作的码农。今日&#xff0c;要和大家分享的是一款基于python的语音识别与蓝牙通信的温控系统毕设项目。项目源码以及部署相关事宜&#xff0c;请联系陈辰学…...

Pandas Series学习

1.Series简介 Pandas Series类似表格的列&#xff08;column&#xff09;&#xff0c;类似于一维数组&#xff0c;可以保存任何数据类型&#xff0c;具有标签&#xff08;索引&#xff09;&#xff0c;使得数据在处理分析时更具灵活性。Series数据结构是非常有用的&#xff0c;…...

为什么要探索太空?这对我们有什么好处?

几个世纪以来&#xff0c;人类一直着迷于宇宙的奥秘&#xff0c;这驱使我们冒险离开地球&#xff0c;去探索太阳系之外的未知环境。在当今世界&#xff0c;我们为什么要进行太空探索之旅这个问题&#xff0c;远不止出于单纯的好奇。 归根结底&#xff0c;太空探索是一种必要之…...

uniapp开发【选择地址-省市区功能】,直接套用即可

一、效果展示 二、代码 <template><view><view class="user_info"><view class="item"...

3个模型的交互式多模型IMM,基于EKF的目标跟踪实例(附MATLAB代码)

文章目录 3个模型的IMM源代码运行结果代码介绍总结 3个模型的IMM 代码实现了基于 I M M IMM IMM&#xff08;Interacting Multiple Model&#xff09;算法的目标跟踪。它使用三种不同的运动模型&#xff08;匀速直线运动、左转弯和右转弯&#xff09;来预测目标的位置&#x…...

利用游戏引擎的优势

大家好&#xff0c;我是小蜗牛。 在当今快速发展的游戏产业中&#xff0c;选择合适的游戏引擎对开发者来说至关重要。Cocos Creator作为一款功能强大且灵活的游戏引擎&#xff0c;为开发者提供了丰富的工具和资源&#xff0c;使他们能够高效地开发出优秀的游戏。本文将探讨如何…...

一致角色的视频且唇形同步中文配音和免费音效添加

现在AI可以免费生成不带水印、不限时长的视频了&#xff0c;并且视频里的角色可以进行唇形同步配音。最重要的是&#xff0c;我还会分享给大家&#xff0c;怎么生成角色一致的动画场景&#xff0c;怎么使用场景图片生成完整的视频&#xff0c;并且我还会介绍一款&#xff0c;我…...

Spring学习笔记_14——@Qualifier

Qualifier 1. 解释 当Spring中存在多个类型相同但是名称不同的Bean时&#xff0c;使用Autowired注解向类的构造方法、方法、参数、字段中注入Bean对象时&#xff0c;首先会根据Bean的类型注入&#xff0c;如果存在多个类型相同的Bean时&#xff0c;会根据Bean的名称注入&…...

高级SQL技巧详解与实例

在数据处理与分析领域&#xff0c;高级SQL技巧是提升效率与准确性的关键。本文将结合参考资料&#xff0c;对高级SQL技巧进行系统的整理与解读&#xff0c;并通过实例展示其应用。 一、窗口函数 窗口函数是一种在SQL中执行复杂计算的强大工具&#xff0c;它们允许用户在一组行…...

实现PC端和安卓手机的局域网内文件共享

文章目录 一、准备工作1.1 笔记本(Win10)的设置&#xff08;主要可分为3大部分&#xff1a;更改共享设置、创建本地用户、选择共享文件&#xff09;1.2 台式机(Win7)的设置 二、实现共享文件夹的访问2.1 笔记本(Win10)访问台式机(Win7)2.2 台式机(Win7)访问笔记本(Win10)(一定要…...

腾讯云云开发深度解读:云数据库、云模板与AI生成引用的魅力

腾讯云云开发平台为开发者和潜在用户提供了丰富的解决方案&#xff0c;其中的云数据库、云模板和AI生成引用等产品尤为引人注目。这篇文件是我个人对这些产品的能力、应用场景、业务价值、技术原理的介绍和深度解读&#xff0c;最后也简单写一下新手如何进行相关产品的初步使用…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

【C++】纯虚函数类外可以写实现吗?

1. 答案 先说答案&#xff0c;可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...