SpringBoot实现轻量级动态定时任务管控及组件化
1关于动态定时任务
关于在SpringBoot中使用定时任务,大部分都是直接使用SpringBoot的@Scheduled注解,如下:
@Component
public class TestTask
{@Scheduled(cron="0/5 * * * * ? ") //每5秒执行一次public void execute(){SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.info("任务执行" + df.format(new Date()));}
}
或者或者使用第三方的工具,例如XXL-Job等。就XXL-Job而言,如果说是大型项目,硬件资源和项目环境都具备,XXL-Job确实是最佳的选择,可是对于项目体量不大,又不想过多的引入插件;使用XXL-Job多少有点“杀鸡用牛刀”的意思;
之所以这样说,是因为在SpringBoot中集成使用XXL-Job的步骤如下:
-
引入依赖,配置执行器Bean
-
在自己项目中编写定时任务代码
-
部署XXL-Job
-
登录XXL-Job调度中心的 Web 控制台,创建一个新的任务,选择刚才配置的执行器和任务处理器,设置好触发条件(如 Cron 表达式)和其他选项后保存
-
生产环境下,还要把配置好任务的XXL-Job和项目一起打包
@Component
public class SampleXxlJob {@XxlJob("sampleJobHandler")public void sampleJobHandler() throws Exception {// 业务逻辑System.out.println("Hello XXL-JOB!");}
}
这一套步骤在中小型项目中,明显成本大于效果,而使用XXL-Job无非就是想动态的去管理定时任务,可以在运行状态下随意的执行、中断、调整执行周期、查看运行结果,而不是像基于@Scheduled注解实现后,无法改变。
所以,这里就基于SpringBoot实现动态调度定时任务,之前针对这个问题,我写过一篇CSDN文章(连接放在下方),最近博主将相关的代码进行了汇总,并且在易用性和扩展性上进行了加强,基于COLA架构理论,封装到了组件层
这次加强主要包括:
-
剥离了任务的持久化,使其依赖更简洁,真正以starter的形式开箱即用
-
扩展了方法级的定时任务注册,能够像xxl-job一样,一个注解搞定动态定时任务的注册及管理
2动态定时任务实现思路
关于动态定时任务的核心思路是反射+定时任务模板,这两部分的核心框架不变,这里主要是针对强化的第二点进行思路解释,第二点的强化是加入了类扫描机制,通过扫描,实现了自动注册,规避了之前每新增一个定时任务都必须得预制SQL的步骤:
类级别定时任务实现思路:在原模板模式的基础下,基于AbstractBaseCronTask类自定义的定时任务子类作为类级别定时任务,即一个类为一个定时任务,初始时由包扫描所有的子类,并使用反射将其实例化,逐一加入到进程管理中,并激活定时调度。
基于@MethodJob的方法级别任务实现思路:以 AbstractBaseCronTask类为基础,定义一个固定的子类BaseMethodLevelTask,并在其内部限定任务的执行方式,扫描所有标注了@MethodJob的方法及其所属的Bean,连同Bean及方法的反射类作为构造函数,生成BaseMethodLevelTask对象,因为BaseMethodLevelTask也是AbstractBaseCronTask的子类,则可以以类级别定时任务的方式,将其生成定时任务,并进行管理。
本质还是管理的AbstractBaseCronTask子类在线程池中的具体对象,不同的地方是类级别定时任务是一个具体的任务类仅生成一个对象,class路径即是唯一的标识,而方法级别的定时任务均基于BaseMethodLevelTask生成无数个对象,具体标识则是构造函数传入的Bean的反射对象和方法名。
对此部分感兴趣的可以一起参与开发,该项目地址:Gitee源码,主要为其中task-component模块。
3组件使用方法
根据Git地址,将源码down下,编译安装到本地私仓中,以Maven的形式引入即可,该组件遵循Spring-starter规范,开箱即用。
<dependency><groupId>com.gcc.container.components</groupId><artifactId>task-component</artifactId><version>1.0.0</version></dependency>
3.1 Yaml配置说明
给出一个yaml模板:
gcc-task:task-class-package : *data-file-path: /opt/myproject/task_info.json
对于task-component的配置只有两个,task-class-package和data-file-path
此处的两个配置项都包含默认值,所以不进行yml的gcc-task
仍旧可以使用该组件
3.2 新建定时任务
对于该组件在进行定时任务的创建时,有两种,分别是类级定时任务和方法级定时任务,两者的区别在于是以类为基本的单位还是以方法为一个定时任务的单位,对于运行效果则并无区别,根据个人喜好,选择使用哪一种即可
类级定时任务
新增一个定时任务逻辑,则需要实现基类AbstractBaseCronTask
,并加入注解 @ClassJob
ClassJob的参数如下:
cron
属性仅在第一次新增该任务时提供一个默认的执行周期,必须填写,后续任务加载后,定时任务相关数据会被存放在文件或数据库中,此时则以文件或数据库中该任务的cron为主,代码中的注解则不会生效,如果想重置,则删除已经持久化的任务即可。
一个完整的Demo如下:
@TaskJob(cron = "10 0/2 * * * ?" ,desc = "这是一个测试任务",bootup = true)
public class TaskMysqlOne extends AbstractBaseCronTask {public TaskMysqlOne(TaskEntity taskEntity) {super(taskEntity);}@Overridepublic void beforeJob() {}@Overridepublic void startJob() {}@Overridepublic void afterJob() {}
}
继承AbstractBaseCronTask
必须要实现携带TaskEntity参数的构造函数
、beforeJob()
、startJob()
、afterJob()
三个方法即可。原则上这三个方法是规范定时任务的执行,实际使用,只需要把核心逻辑放在三个方法中任何一个即可。
因定时任务类是非SpringBean管理的类,所以在自定义的定时任务类内无法使用任何Spring相关的注解(如@Autowired),但是却可以通过自带的getServer(Class<T> className)
方法来获取任何Spring上下文中的Bean
例如,你有一个UserService的接口及其Impl的实现类,想在定时任务类中使用该Bean,则可以:
@TaskJob(cron = "10 0/2 * * * ?" ,desc = "这是一个测试任务",bootup = true)
public class TaskMysqlOne extends AbstractBaseCronTask {public TaskMysqlOne(TaskEntity taskEntity) {super(taskEntity);}@Overridepublic void beforeJob() {}@Overridepublic void startJob() {List<String> names = getServer(UserService.class).searchAllUserName();//后续逻辑……//其他逻辑}@Overridepublic void afterJob() {}
}
方法级定时任务
如果不想新建类,或者不想受限于AbstractBaseCronTask的束缚,则可以像xxl-job定义定时任务一样,直接在某个方法上标注@MethodJob注解即可。
@MethodJob的参数如下:
通ClassJob一样,cron
属性仅在第一次新增该任务时提供一个默认的执行周期,必须填写,后续任务加载后,定时任务相关数据会被存放在文件或数据库中,此时则以文件或数据库中该任务的cron为主,代码中的注解则不会生效,如果想重置,则删除已经持久化的任务即可。
下面是一个例子:
//正常定义的Service接口
public interface AsyncTestService {void taskJob();}//Service接口实现类
@Service
public class AsyncTestServiceImpl implements AsyncTestService {@MethodJob(cron = "11 0/1 * * * ?",desc = "这是个方法级任务")@Overridepublic void taskJob() {log.info("方法级别任务查询关键字为企业的数据");QueryWrapper<ArticleEntity> query = new QueryWrapper<>();query.like("art_name","企业");List<ArticleEntity> data = articleMapper.selectList(query);log.info("查出条数为{}",data.size());}
}
注:该注解仅支持SpringBoot中标注为@Component
、@Service
、@Repository
的Bean
3.3 动态调度任务接口说明
定时任务相关的管理操作均封装在TaskScheduleManagerService
接口中,接口内容如下:
public interface TaskScheduleManagerService {/*** 查询在用任务* @return*/List<TaskVo> searchTask(SearchTaskDto dto);/*** 查询任务详情* @param taskId 任务id* @return TaskEntity*/TaskVo searchTaskDetail(String taskId);/*** 运行指定任务* @param taskId 任务id* @return TaskRunRetDto*/TaskRunRetVo runTask(String taskId);/*** 关停任务* @param taskId 任务id* @return TaskRunRetDto*/TaskRunRetVo shutdownTask(String taskId);/*** 开启任务* @param taskId 任务id* @return TaskRunRetDto*/TaskRunRetVo openTask(String taskId);/*** 更新任务信息* @param entity 实体* @return TaskRunRetDto*/TaskRunRetVo updateTaskBusinessInfo(TaskEntity entity);
}
可直接在外部项目中注入使用即可:
@RestController
@RequestMapping("/myself/manage")
public class TaskSchedulingController {//引入依赖后可直接使用注入@Autowiredprivate TaskScheduleManagerService taskScheduleManagerService;@GetMapping("/detail")@Operation(summary = "具体任务对象")public Response searchDetail(String taskId){return Response.success(taskScheduleManagerService.searchTaskDetail(taskId));}@GetMapping("/shutdown")@Operation(summary = "关闭指定任务")public Response shutdownTask(String taskId){return Response.success(taskScheduleManagerService.shutdownTask(taskId));}@GetMapping("/open")@Operation(summary = "开启指定任务")public Response openTask(String taskId){return Response.success(taskScheduleManagerService.openTask(taskId));}
}
接口效果:
可使用该接口,进行UI页面开发。
3.4 关于任务持久化的扩展
在实现思路中提到过,task-component的执行原理需要将注册后的任务持久化,下次再启动项目时,则直接使用持久化的TaskEntity来加载定时任务。
考虑到定时任务的数量不大,且对于交互要求不高,另外考虑封装成组件的独立性和普适性,不想额外引入数据库依赖和ORM框架,所以组件默认的是以JSON文件的形式进行存储,实际使用中,考虑到便利性,可以自行对持久化部分进行扩展。
所谓持久化,其实本制是持久化TaskEntity对象,TaskEntity对象如下:
@Data
public class TaskEntity implements Serializable {/*** 任务ID(唯一)*/private String taskId;/*** 任务名称*/private String taskName;/*** 任务描述*/private String taskDesc;/*** 遵循cron 表达式*/private String taskCron;/*** 类路径*/private String taskClass;/*** 任务级别 CLASS_LEVEL 类级别,METHOD_LEVEL 方法级别*/private TaskLevel taskLevel;/*** 任务注册时间*/private String taskCreateTime;/*** 是否启用,1启用,0不启用*/private Integer taskIsUse;/*** 是否系统启动后立刻运行 1是。0否*/private Integer taskBootUp;/*** 上次运行状态 1:成功,0:失败*/private Integer taskLastRun;/*** 任务是否在内存中 1:是,0:否*/private Integer taskRamStatus;/*** 外部配置 (扩展待使用字段)*/private String taskOutConfig;/*** 加载配置*/private String loadConfigure;
}
扩展的主要操作为两步:
-
新建存放taskEntity的表
-
实现TaskRepository接口
首先新建数据库表,这里以Mysql为例给出建表语句:
DROP TABLE IF EXISTS `tb_task_info`;
CREATE TABLE `tb_task_info` (`task_id` varchar(100) NOT NULL PRIMARY KEY ,`task_name` varchar(255) DEFAULT NULL,`task_desc` text,`task_cron` varchar(20) DEFAULT NULL,`task_class` varchar(100) DEFAULT NULL COMMENT '定时任务类路径',`task_level` varchar(50) DEFAULT NULL COMMENT '任务级别:类级别(CLASS_LEVEL)、方法级别(METHOD_LEVEL)',`task_is_use` tinyint DEFAULT NULL COMMENT '是否启用该任务,1:启用,0禁用',`task_boot_up` tinyint DEFAULT NULL COMMENT '是否为开机即运行,1:初始化即运行,0,初始化不运行',`task_out_config` text CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci COMMENT '定时任务额外配置项,采用json结构存放',`task_create_time` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL COMMENT '定时任务追加时间',`task_last_run` tinyint DEFAULT NULL COMMENT '任务上次执行状态;1正常,0执行失败,null未知',`task_ram_status` tinyint DEFAULT NULL COMMENT '任务当前状态;1内存运行中,0内存移除',`loadConfigure` text COMMENT '加载相关配置',
PRIMARY KEY (`task_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;
实现TaskEntityRepository 接口,接口内容为:
public interface TaskEntityRepository {/*** 新增数据* @param entity* @return int*/int save(TaskEntity entity);/*** 删除任务,根据TaskId* @param id id* @return int*/int removeByTaskId(String id);/*** 更新任务(除taskId外,所有字段必须更新)* @param entity 实体* @return int*/int update(TaskEntity entity);/*** 查询全部任务* @return List<TaskEntity>*/List<TaskEntity> queryAllTask();}
只需要新建类,然后实现该接口即可,如下是基于Mybatis-Plus进行的实现样例:
@Mapper
public interface TaskDataMapper extends BaseMapper<TaskEntity> {
}@Repository
//此处一定要用@Primary注解进行固定
@Primary
public class TaskEntityReponsitoryImpl implements TaskEntityRepository {@Autowiredprivate TaskDataMapper taskDataMapper;@Overridepublic int save(TaskEntity entity) {entity.setTaskCreateTime(DateUtil.now());return taskDataMapper.insert(entity);}@Overridepublic int removeByTaskId(String id) {QueryWrapper<TaskEntity> query = new QueryWrapper<>();query.eq("task_id",id);return taskDataMapper.delete(query);}@Overridepublic int update(TaskEntity entity) {UpdateWrapper<TaskEntity> update = new UpdateWrapper<>();update.eq("task_id",entity.getTaskId());return taskDataMapper.update(entity,update);}@Overridepublic List<TaskEntity> queryAllTask() {return taskDataMapper.selectList(new QueryWrapper<>());}
}
至此,项目中则可以以数据库表的形式来管理定时任务:
任务运行日志:
[main] com.web.test.Application : Started Application in 3.567 seconds (JVM running for 4.561)
[main] .g.c.c.t.c.InitTaskSchedulingApplication : 【定时任务初始化】 容器初始化
[main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService
[main] .g.c.c.t.c.InitTaskSchedulingApplication : 【定时任务初始化】定时任务初始化任务开始
[main] c.g.c.c.task.compont.TaskScheduleImpl : 【定时任务初始化】装填任务:TaskTwoPerson [ 任务执行周期:15 0/2 * * * ? ] [ bootup:0]
[main] c.g.c.c.task.compont.TaskScheduleImpl : 【定时任务初始化】装填任务:TaskMysqlOne [ 任务执行周期:10 0/2 * * * ? ] [ bootup:1]
[main] c.g.c.c.task.compont.TaskScheduleImpl : 【定时任务初始化】装填任务:taskJob [ 任务执行周期:11 0/1 * * * ? ] [ bootup:0]
[main] .g.c.c.t.c.InitTaskSchedulingApplication : 【定时任务初始化】定时任务初始化任务完成
[main] c.g.c.c.task.service.AfterAppStarted : 【定时任务自运行】运行开机自启动任务
[main] TaskMysqlOne : ---------------------任务 TaskMysqlOne 开始执行-----------------------
[main] TaskMysqlOne : 任务描述:这是一个测试任务
[main] TaskMysqlOne : 我是张三
[main] TaskMysqlOne : 任务耗时:约 0.0 s
[main] TaskMysqlOne : ---------------------任务 TaskMysqlOne 结束执行-----------------------[task-thread-1] taskJob : ---------------------任务 taskJob 开始执行-----------------------
[task-thread-1] taskJob : 任务描述:这是个方法级任务
[task-thread-1] c.w.t.service.impl.AsyncTestServiceImpl : 方法级别任务查询关键字为企业的数据
[task-thread-1] c.w.t.service.impl.AsyncTestServiceImpl : 查出条数为1
[task-thread-1] taskJob : 任务耗时:约 8.45 s
[task-thread-1] taskJob : ---------------------任务 taskJob 结束执行-----------------------
文章转载自:糖拌西红柿
原文链接:SpringBoot实现轻量级动态定时任务管控及组件化 - 糖拌西红柿 - 博客园
体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构
相关文章:
SpringBoot实现轻量级动态定时任务管控及组件化
1关于动态定时任务 关于在SpringBoot中使用定时任务,大部分都是直接使用SpringBoot的Scheduled注解,如下: Component public class TestTask {Scheduled(cron"0/5 * * * * ? ") //每5秒执行一次public void execute(){SimpleDa…...
STM32 FreeRTOS 任务挂起和恢复---实验
实验目标 学会vTaskSuspend( )、vTaskResume( ) 任务挂起与恢复相关API函数使用: start_task:用来创建其他的三个任务。 task1:实现LED1每500ms闪烁一次。 task2:实现LED2每500ms闪烁一次。 task3:判断按键按下逻辑,KE…...
#漏洞挖掘# 一文了解什么是Jenkins未授权访问!!!
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
1.21学习记录
misc 2023isctf 你说爱我尊嘟假嘟 这题有点脑洞,需要把你说爱我换成Ook.将尊嘟换为Ook!假嘟换成Ook?(根据语气进行猜测吧)用在线工具解密最后用base64解密即可 2023isctf 杰伦可是流量明星 解压后是一个MP3文件&am…...
【Pandas】pandas Series groupby
Pandas2.2 Series Function application, GroupBy & window 方法描述Series.apply()用于将一个函数应用到 Series 的每个元素或整个 SeriesSeries.agg()用于对 Series 数据进行聚合操作Series.aggregate()用于对 Series 数据进行聚合操作Series.transform()用于对 Series…...
Text2SQL 智能报表方案介绍
0 背景 Text2SQL智能报表方案旨在通过自然语言处理(NLP)技术,使用户能够以自然语言的形式提出问题,并自动生成相应的SQL查询,从而获取所需的数据报表,用户可根据得到结果展示分析从而为结论提供支撑&#…...
51c~SLAM~合集1
我自己的原文哦~ https://blog.51cto.com/whaosoft/12327374 #GSLAM 自动驾驶相关~~~ 一个通用的SLAM架构和基准 GSLAM:A General SLAM Framework and Benchmark 开源代码:https://github.com/zdzhaoyong/GSLAM SLAM技术最近取得了许多成功&am…...
服务器安装ESXI7.0系统及通过离线包方式升级到ESXI8.0
新到了一台物理服务器需要安装系统,项目不急用,先拿来做些实验。 本次实验目标: 1、在物理服务器上安装ESXI7.0系统; 2、通过离线包升级方式将ESXI7.0升级为ESXI8.0。 实验环境准备: 物理服务器1台,型号…...
计算机网络 (52)秘钥分配
一、重要性 在计算机网络中,密钥分配是密钥管理中的一个核心问题。由于密码算法通常是公开的,因此网络的安全性主要依赖于密钥的安全保护。密钥分配的目的是确保密钥在传输过程中不被窃取或篡改,同时确保只有合法的用户才能获得密钥。 二、方…...
xctf-comment(Intruder,git恢复,SQL注入,Hex解码)
这题是2018年网鼎杯真题,考察 Burp Suite 的 Intruder 模块去找用户密码,使用 githacker 恢复代码(githack不行),代码审计发现SQL二次注入,尝试SQL注入读取文件内容,读取的是/home/www/.bash_hi…...
Docker Compose创建镜像服务
什么是Docker Compose 使用Docker Compose,可以使用YAML配置文件(称为Compose文件)来配置应用程序的服务,然后使用Compose CLI从配置中创建并启动所有服务 。 Compose文件的默认路径是compose.yaml(首选)…...
kafka学习笔记5 PLAIN认证——筑梦之路
在Kafka中,SASL(Simple Authentication and Security Layer)机制包括三种常见的身份验证方式: SASL/PLAIN认证:含义是简单身份验证和授权层应用程序接口,PLAIN认证是其中一种最简单的用户名、密码认证方式&…...
Walrus Learn to Earn计划正式启动!探索去中心化存储的无限可能
本期 Learn to Earn 活动将带领开发者和区块链爱好者深入探索 Walrus 的技术核心与实际应用,解锁分布式存储的无限可能。参与者不仅能提升技能,还能通过完成任务赢取丰厚奖励!🌊 什么是 Walrus? 数据主权如今正成为越…...
Linux学习笔记
1、什么是Linux Linux,一般指GNU/Linux(单独的Linux内核并不可直接使用,一般搭配GUN套件,故得此称呼),是一种免费使用和自由传播的类UNIX操作系统。它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用…...
解锁电商设计新速度:StartAI插件制作产品图实操教程
在电商设计这片竞争激烈的战场上,每一位设计师都在追求高效与创意的完美融合。繁琐的背景抠图、单一的设计模板、紧迫的时间周期,常常让我们力不从心。但现在,StartAI插件的问世,为我们的设计之路带来了革命性的改变。下面&#x…...
AutoPrompt框架和实操:如何用AutoPrompt完成电影评论和聊天审核任务?
1. AutoPrompt框架概述 1.1 框架定义与目标 AutoPrompt是一个旨在提升和完善用户提示以适应现实世界用例的提示优化框架。该框架通过迭代生成具有挑战性的边缘案例数据集,并相应地优化提示,从而自动生成针对用户意图量身定制的高质量、详细的提示。其核心目标是利用大型语言…...
修复 Kubernetes Deployment 修改后未生效的问题
在 Kubernetes 集群中,当尝试修改某些 Deployment 资源(如 calico-kube-controllers)的 image 配置时,发现修改总是未生效,并恢复到原样。这种问题通常是因为 Deployment 资源受到其他控制器(如 Operator&a…...
Excel 技巧17 - 如何计算倒计时,并添加该倒计时的数据条(★)
本文讲如何计算倒计时,并添加该倒计时的数据条。 1,如何计算倒计时 这里也要用公式 D3 - TODAY() 显示为下面这个样子的 然后右键该单元格,选 设置单元格格式 然后点 常规 这样就能显示出还书倒计时的日数了。 下拉适用到其他单元格。 2&a…...
Golang Gin系列-5:数据模型和数据库
在这篇Gin教程的博客中,我们将探索如何将模型和数据库与Gin框架无缝集成,使你能够构建健壮且可扩展的web应用程序。通过利用流行的库并遵循最佳实践,你将学习如何定义模型、建立数据库连接、执行CRUD操作以及确保基于gin的项目中的数据完整性…...
Android系统开发(十九):无缝拉伸的艺术——9-Patch 可绘制对象详解
引言 在移动开发中,背景、标题以及其他界面元素的设计质量直接影响用户体验。然而,如何让图片适应不同分辨率设备,成为开发者常常头疼的问题。这时,9-Patch 闪亮登场!它不仅可以无缝拉伸,还能保持视觉效果…...
物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境:飞腾派开发板(国产E2000处理器) 软件环境:飞腾派OS(Phytium Pi OS) 硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板…...
计算机网络 (51)鉴别
前言 计算机网络鉴别是信息安全领域中的一项关键技术,主要用于验证用户或信息的真实性,以及确保信息的完整性和来源的可靠性。 一、目的与重要性 鉴别的目的是验明用户或信息的正身,对实体声称的身份进行唯一识别,以便验证其访问请…...
Mellanox ConnectX 系列网卡的双驱动架构:以太网与 InfiniBand 的协同设计
在现代数据中心和高性能计算(HPC)环境中,网络硬件的性能和功能至关重要。Mellanox ConnectX 系列网卡以其卓越的性能和多功能性而闻名,支持从传统的以太网到高性能的 InfiniBand 网络协议。这种多功能性使得 Mellanox 网卡能够满足不同应用场景的需求,从常规的数据中心网络…...
【Java】阿里环球Antom支付对接
阿里环球Antom支付对接 线上文档地址: GitHub:https://github.com/alipay/global-open-sdk-java 文档:https://global.alipay.com/docs/ac/ams_zh-cn/session_cashier maven: <!--阿里国际支付--><dependency><g…...
【vim】vim编辑器如何设置行号
vim编辑器如何设置行号 一、**临时设置行号**二、永久设置行号2.1. **用户配置文件方式(针对当前用户)**2.2. **全局配置文件方式(谨慎使用,会影响所有用户)** 在Vim中设置行号有以下两种常见的方法: 一、…...
爬虫基础之爬取某站视频
目标网址:为了1/4螺口买小米SU7,开了一个月,它值吗?_哔哩哔哩_bilibili 本案例所使用到的模块 requests (发送HTTP请求)subprocess(执行系统命令)re (正则表达式操作)json (处理JSON数据) 需求分析: 视频的名称 F12 打开开发者工具 or 右击…...
2024嵌入式系统的未来发展与技术洞察分享
时间如白驹过隙,不知不觉又是一年,这一年收获满满。接下来,将本年度对技术的感悟和洞察分析如下,希望对大家有所帮助。 在过去几十年里,嵌入式系统技术迅速发展,成为现代电子设备和智能硬件的核心组成部分。…...
[微服务]注册中心优化
环境隔离 企业实际开发中,往往会搭建多个运行环境,例如: 开发环境测试环境预发布环境生产环境 这些不同环境之间的服务和数据之间需要隔离。 还有的企业中,会开发多个项目,共享nacos集群。此时,这些项目…...
Leetcode 3426. Manhattan Distances of All Arrangements of Pieces
Leetcode 3426. Manhattan Distances of All Arrangements of Pieces 1. 解题思路2. 代码实现 题目链接:3426. Manhattan Distances of All Arrangements of Pieces 1. 解题思路 这道题很惭愧,一开始没有搞定,后来看了答案想了想ÿ…...
【重庆市乡镇界】面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移内容测评
标题中的“最新重庆市乡镇界面图层shp格式arcgis数据乡镇名称和编码wgs84坐标无偏移最新”指的是一个地理信息系统(GIS)的数据集,特别设计用于ArcGIS软件。这个数据集包含了重庆市所有乡镇的边界信息,以Shapefile(.shp…...
基于ChatGPT的论文写作辅助工具研究
**基于ChatGPT的论文写作辅助工具研究** **摘要**: 随着人工智能技术的飞速发展,自然语言处理(NLP)领域取得了显著进步。ChatGPT作为OpenAI最新推出的生成式预训练Transformer模型,在文本生成、对话系统等方面展现出…...
定时器setTimeout和setInterval
setTimeOut()异步 setInterval()异步...
PCL 部分点云视点问题【2025最新版】
目录 一、问题概述二、解决方案1、软件实现2、代码实现三、调整之后博客长期更新,本文最近更新时间为:2025年1月18日。 一、问题概述 针对CloudCompare软件处理过的pcd格式点云,在使用PCL进行特征点提取、配准等实验中最终显示结果出现点云位置偏差较大的问题,本博客给出解…...
Cursor 与常见集成开发环境(IDE)的优势对比
Cursor与常见集成开发环境(IDE)的优势对比 一、AI 辅助编程能力 强大的代码生成功能: Cursor: 以其内置的强大 AI 辅助编程功能为核心优势。用户可以通过输入自然语言描述,快速生成各种编程语言的代码。例如…...
TDengine 做为 FLINK 数据源技术参考手册
Apache Flink 是一款由 Apache 软件基金会支持的开源分布式流批一体化处理框架,可用于流处理、批处理、复杂事件处理、实时数据仓库构建及为机器学习提供实时数据支持等诸多大数据处理场景。与此同时,Flink 拥有丰富的连接器与各类工具,可对接…...
不重启JVM,替换掉已经加载的类
不重启JVM,替换掉已经加载的类 直接操作字节码 使用ASM框架直接操作class文件,在类中修改代码,然后retransform就可以了 下边是BTrace官方提供的一个简单例子: package com.sun.btrace.samples;import com.sun.btrace.annotati…...
axios的使用总结
一、Axios 简介 Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。在 Vue 项目中,它主要用于发送 HTTP 请求来获取数据(如从 API 获取数据)或者提交数据(如用户登录、注册等表单数据)。 二…...
使用 F12 查看 Network 及数据格式
在浏览器中,F12 开发者工具的 “Network” 面板是用于查看网页在加载过程中发起的所有网络请求,包括 API 请求,以及查看这些请求的详细信息和响应数据的。以下以常见的 Chrome 浏览器为例,介绍如何使用 F12 控制台查看 Network 里…...
HTML<img>标签
例子 如何插入图片: <img src"img_girl.jpg" alt"Girl in a jacket" width"500" height"600"> 下面有更多“自己尝试”的示例。 定义和用法 该<img>标签用于在 HTML 页面中嵌入图像。 从技术上讲&#x…...
Android系统开发(六):从Linux到Android:模块化开发,GKI内核的硬核科普
引言: 今天我们聊聊Android生态中最“硬核”的话题:通用内核镜像(GKI)与内核模块接口(KMI)。这是内核碎片化终结者的秘密武器,解决了内核和供应商模块之间无尽的兼容性问题。为什么重要&#x…...
每日一刷——1.20——准备蓝桥杯
链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目一 请统计某个给定范围[L, R]的所有整数中,数字2出现的次数。 比如给定范围[2, 22],数字2在数2中出现了1次,在数12中出现1次,在数20中出现1次&a…...
知行合一:解决有心无力的问题,解决知易行难的问题,知行合一并不意味着事事都要合一,而是....
问题是什么? 想学习的时候,有手机阻碍我们。想戒掉手机短视频,卸载后,几天的时间,又下载了回来。制定了减肥计划,但就是不执行。明知道这样做是不对的,但依然行动不起来。 沉溺于各种各样的享…...
C++ Qt练习项目 日期时间数据 未完待续
个人学习笔记 新建项目 设计UI 实现组件功能 参考资料 4.7日期时间数据_哔哩哔哩_bilibili...
Golang学习笔记_28——工厂方法模式(实例)
Golang学习笔记_26——通道 Golang学习笔记_27——单例模式 Golang学习笔记_28——工厂方法模式 工厂方法模式(实例) package factory_method_demoimport "fmt"// Order 接口,定义订单的基本操作 type Order interface {Calculate…...
linux下springboot项目nohup日志或tomcat日志切割处理方案
目录 1. 配置流程 2. 配置说明 其他配置选项: 3. 测试执行 4. 手动执行 https://juejin.cn/post/7081890486453010469 通常情况下,我们的springboot项目部署到linux服务器中,通过nohup java -jar xxx.jar &指令来进行后台运行我们…...
SentencePiece和 WordPiece tokenization 的含义和区别
SentencePiece和 WordPiece tokenization 的含义和区别 SentencePiece 和 WordPiece 都是常用的分词(tokenization)技术,主要用于自然语言处理(NLP)中的文本预处理,尤其是在处理大规模文本数据时。它们都基于子词(subword)单元,能够将未登录词(out-of-vocabulary, O…...
视频修复最强算法 部署笔记2025
目录 模型下载: 模型: 原版保存的视频,vs code不播放: 模型下载: Release ProPainter V0.1.0 Release sczhou/ProPainter GitHub huggingface-cli download --resume-download lixiaowen/diffuEraser --local-dir /mnt/pfs/models/huggingface/models--lixiaowen--d…...
Java数据结构——优先队列
目录 引言1. 优先队列2. 优先队列的实现2.1 堆的概念2.2 堆的创建2.2.1 堆的向下调整2.3 堆的插入2.4 堆的删除 3. 总结 引言 前面一篇文章讲了二叉树,本篇将讲述数据结构中的优先队列,优先队列则需要用到完全二叉树来实现。 1. 优先队列 队列&#x…...
红外热成像之无人机载荷
电力巡检 相较于传统的人工电力巡线方式,无人机巡检能够在高空对人工难以达到或无法检测的设备进行检测,实现了电子化、信息化、智能化巡检,可以提高巡检的工作效率和应急抢险水平。 森林防火 无人机搭载红外光电系统能在森林高空进行全天候监…...
深入Spring Boot:自定义Starter开发与实践
引言 Spring Boot通过其强大的自动配置机制和丰富的Starter模块,极大地简化了Spring应用的开发过程。Starter模块封装了一组相关的依赖和配置,使得开发者可以通过简单的依赖引入,快速启用特定的功能。然而,除了使用Spring Boot提…...