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

Java定时任务实现方案(四)——Spring Task

Spring Task

这篇笔记,我们要来介绍实现Java定时任务的第四个方案,使用Spring Task,以及该方案的优点和缺点。

​ Spring Task是Spring框架提供的一个轻量级任务调度框架,用于简化任务调度的开放,通过注解或XML配置的方式,可以轻松实现定时任务、异步任务等功能,我们这里主要介绍它的定时任务。

使用
1.添加依赖

​ 既然要使用Spring框架提供的SpringTask,我们就要引入相关的依赖,同时,我们后面要通过自定义注解+AOP的方式实现任务监听,所以也要引入SpringAop的相关依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>3.3.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>3.3.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>3.3.0</version></dependency>
2.启用定时任务支持

​ 要使用SpringTask实现定时任务,我们首先要启用定时任务支持,这个我们只需要在Spring应用的启动类上加上@EnableScheduling就可以了。

@SpringBootApplication
@EnableScheduling
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class,args);}
}
3.配置定时任务注册器

​ 我们可以通过配置类,对SpringTask执行定时任务的调度器进行相关的配置和初始化,并注册到Spring容器中,便于统一管理调度任务。

@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {/*** 配置定时任务处理方式** @param taskRegistrar 定时任务注册器,用于管理和调度定时任务*/@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {// 创建一个线程池任务调度器ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();//设置线程池大小taskScheduler.setPoolSize(10);// 设置线程名称前缀,便于识别和管理taskScheduler.setThreadNamePrefix("perform-");// 初始化线程池任务调度器taskScheduler.initialize();// 将任务调度器设置到定时任务注册器中,以便统一管理调度任务taskRegistrar.setTaskScheduler(taskScheduler);}
}
4.创建定时任务

​ 接着,我们就可以编写定时任务了,这里我们采用注解的形式提供示例。只需要在外面的定时方法上面加上一个@Scheduled注解,Spring容器就可以帮我们实现定时任务了。这个@Scheduled注解可以设置一些参数便于更灵活的调度任务,例如fixedRate参数可以让我们设置间隔多长时间执行一次、initialDelay参数可以设置第一次执行任务前延迟的时间,fixedDelay参数也可以设置每一次延迟多长时间再执行定时任务。同时,该注解还支持使用cron表达式来灵活的设置任务调度的方式。

@Component
@ConditionalOnProperty(prefix = "scheduled",name = "task.enabled",havingValue = "true")//条件注解控制定时任务的启用和禁用
public class ScheduledTask {/*** 每5s执行一次*/@Scheduled(fixedRate = 5000)@TaskListenerpublic void performTask1(){System.out.println(getTime()+"执行定时任务1");}/*** 每分钟的第10s执行一次*/@Scheduled(cron = "10 * * * * ?")@TaskListenerpublic void performTask2(){System.out.println(getTime()+"执行定时任务2");}/*** 第一次执行任务前的延迟时间1s,后面每隔5s执行一次*/@Scheduled(initialDelay = 1000,fixedDelay = 5000)@TaskListenerpublic void performTask3(){System.out.println(getTime()+"执行定时任务3");}/*** 获取当前系统时间* @return*/public static String getTime(){//获取当前的系统时间LocalDateTime now = LocalDateTime.now();//定义时间格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//格式化时间return now.format(formatter);}
}

​ 这里需要补充的是,我们可以使用条件注解来控制定时任务的启动或禁止。

scheduled:task:enabled: true
补充知识点:cron表达式

​ cron表达式是一种用于指定定时任务执行时间的字符串格式,广泛用于Linux系统的cron作业调度器以及各种编程框架中。

​ 一个标准的CRON表达式由6个或7个字段组成(取决于是否包含年份字段),各字段之间用空格分隔:[秒] [分钟] [小时] [日期] [月份] [星期] [年份] (可选)

​ 各字段的取值范围如下:

字段范围
0-59
分钟0-59
小时0-23
日期1-31
月份1-12或JAN-DEC
星期0-7或SUN-SAT(0和7都表示星期日)
年份(可选)1970-2099

​ 常见符号说明:

符号含义
*表示该字段的所有可能值,例如*在分钟字段表示每分钟
,分隔多个具体的值,例如1,15表示第1分钟和第15分钟
-定义一个值范围,例如10-15表示从第10分钟到第15分钟
/指定增量,例如*/5表示每隔5个单位执行一次
?用于日期或星期字段,表示不指定明确的值,通常用于其中一个字段时,另一个字段有具体值
L表示最后一天或最后一个工作日,例如L在日期字段表示每月最后一天。
W表示最近的工作日,例如15W表示离15号最近的工作日
#用于星期字段,表示某个月的第几个星期几,例如2#3表示每月的第三个星期二

​ 注意:cron表达式的星期和日期不能同时为具体的值,如果同时指定具体的值,可能会导致逻辑冲突或不明确的行为。

​ 示例:

cron表达式含义
0 30 * * * ?每小时第30分钟执行
0 0 2 * * ?每天凌晨2点执行
0 0 8 ? * MON每周一的上午8点执行
0 0 0 L * ?每月的最后一天的午夜执行
0 0/5 * * * ?每5分钟执行一次
5.通过自定义注解+AOP实现任务监听(可选)

​ 如果需要对定时任务进行监听并做出其他相应的处理的话,我们还可以自己通过自定义注解+AOP的方式实现任务监听器来进行监听处理。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TaskListener {
}
@Component
@Aspect
public class TaskListenerAspect {@Before("@annotation(xiaoxin.Timer.SpringTask.TaskListener)")public void beforeTask(JoinPoint joinPoint){System.out.println("task:"+joinPoint.getSignature().getName()+" 即将开始...");}@After("@annotation(xiaoxin.Timer.SpringTask.TaskListener)")public void afterTask(JoinPoint joinPoint){System.out.println("task:"+joinPoint.getSignature().getName()+" 已结束...");}
}
优点
1.简单易用

​ Spring Task提供了非常简洁的API,通过@Scheduled注解即可轻松定义定时任务,无需复杂的配置,对于简单的定时任务需求,开发者可以快速上手并实现。

2.集成方便

​ Spring Task与Spring框架无缝集成,可以直接利用Spring的依赖注入、事务管理等功能,可以直接在Spring容器管理的Bean中定义定时任务方法,减少额外的配置和代码量。

3.灵活性高

​ Spring Task支持多种调度方式,包括固定延迟(fixedDelay)、固定速率(fixedRate)以及cron表达式,可以根据实际需求灵活选择。还可以结合AOP和自定义注解,添加日志记录和性能监控,增添定时任务的功能。

4.轻量级

​ Spring Task不需要引入额外的重量级调度框架(如Quartz),适合中小型项目或对调度功能要求不高的场景,减少了项目依赖的复杂度和维护成本。

5.线程池支持

​ Spring Task内置线程池支持,可以通过配置文件或Java配置类调整线程池大小,优化任务执行效率,适用与并发执行多个定时任务的场景,确保任务不会因为线程资源不足而阻塞。

6.易于测试

​ 定时任务方法是普通的Java方法,可以通过单元测试工具进行测试。

缺点
1.调度精度有限

​ Spring Task 的调度依赖于JVM线程调度器,因此在高并发或系统负载较高的情况下,可能会出现调度延迟,对于需要极高精度的任务(如毫秒级),Spring Task可能无法满足需求。

2.缺乏分布式支持

​ Spring Task本身不支持分布式调度,如果应用程序部署在多个节点上,每个节点都会独立执行定时任务,可能导致任务重复执行,因此需要额外引入分布式锁机制(如Redis、数据库等)来确保任务只在一个节点上执行。

3.配置灵活性不足

​ 虽然Spring Task可以通过cron表达式实现复杂的调度逻辑,但对于更复杂的调度需求(如动态调整任务执行时间),Spring Task 的配置显得不够灵活,动态修改任务调度规则时,通常需要重启应用或手动触发重新加载配置。

4.错误处理和重试机制较弱

​ Spring Task没有内置的任务失败重试机制,如果任务执行过程中发生异常,默认情况下不会自动重试,需要开发者自行实现错误处理和重试逻辑,增加了开发的复杂度。

5.监控和管理功能较弱

​ Spring Task缺乏内置的任务监控和管理功能,难以实时查看任务的执行状态和历史记录等信息。

6.线程池配置复杂

​ 默认情况下,Spring Task使用的是单一线程池,对于大量任务或长时间运行的任务,可能会导致阻塞,需要手动配置线程池参数(如核心线程数、最大线程数、队列大小等),并根据实际业务需要进行调优。

相关文章:

Java定时任务实现方案(四)——Spring Task

Spring Task 这篇笔记&#xff0c;我们要来介绍实现Java定时任务的第四个方案&#xff0c;使用Spring Task&#xff0c;以及该方案的优点和缺点。 ​ Spring Task是Spring框架提供的一个轻量级任务调度框架&#xff0c;用于简化任务调度的开放&#xff0c;通过注解或XML配置的…...

WGCLOUD运维工具从入门到精通 - 如何设置主题背景

需要升级到WGCLOUD的v3.5.7或者以上版本&#xff0c;才会支持自定义设置主题背景色 WGCLOUD下载&#xff1a;www.wgstart.com 我们登录后&#xff0c;在右上角点击如下的小图标&#xff0c;就可以设置主题背景色了&#xff0c;包括&#xff1a;经典白&#xff08;默认&#x…...

Babylon.js 中的 setHardwareScalingLevel和getHardwareScalingLevel:作用与配合修改内容

在 Babylon.js 中&#xff0c;Engine类提供了setHardwareScalingLevel和getHardwareScalingLevel方法&#xff0c;用于管理和调整渲染分辨率与屏幕分辨率的比例。这些方法在优化性能和提升画质方面非常有用。尤其是在某些平台不支持硬件反锯齿时&#xff0c;可以考虑使用setHar…...

Qwen2-VL:在任何分辨率下增强视觉语言模型对世界的感知 (大型视觉模型 核心技术 分享)

摘要 我们推出了Qwen2-VL系列,这是对之前Qwen-VL模型的高级升级,重新定义了视觉处理中的常规预设分辨率方法。Qwen2-VL引入了Naive Dynamic Resolution机制,使模型能够动态地将不同分辨率的图像转换为不同的视觉令牌数量。这种方法允许模型生成更高效和准确的视觉表示,紧密…...

Docker——入门介绍

目录 1.初识 Docker1.1.什么是 Docker1.1.1.应用部署的环境问题1.1.2.Docker 解决依赖兼容问题1.1.3.Docker 解决操作系统环境差异1.1.4.小结 1.2.Docker 和虚拟机的区别1.3.Docker 架构1.3.1.镜像和容器1.3.2.DockerHub1.3.3.Docker 架构1.3.4.小结 1.4.安装 Docker1.4.1.概述…...

02数组+字符串+滑动窗口+前缀和与差分+双指针(D2_字符串(D2_刷题练习))

目录 1. 最长公共前缀 1.1. 题目描述 1.2. 解题方案 方案一&#xff1a;纵向对比 方案二&#xff1a;横向对比 方案三&#xff1a;最值对比 方案四&#xff1a;分治 方案五&#xff1a;二分 1.3. 知识归纳 2. 左旋转字符串&#xff08;简单&#xff09; 2.1. 题目描述…...

【redis进阶】集群 (Cluster)

目录 一、基本概念 二、数据分片算法 2.1 哈希求余 2.2 一致性哈希算法 3.3 哈希槽分区算法 (Redis 使用) 三、集群搭建 (基于 docker) 3.1 创建目录和配置 3.2 编写 docker-compose.yml 3.3 启动容器 3.4 构建集群 四、主节点宕机 4.1 处理流程 五、集群扩容 六、集群缩容 (选…...

Python案例--100到200的素数

一、问题描述 素数&#xff08;Prime Number&#xff09;是指在大于1的自然数中&#xff0c;除了1和它本身以外不再有其他因数的数。判断一个数是否为素数是计算机科学和数学中的一个经典问题。本实例的目标是找出101到200之间的所有素数&#xff0c;并统计它们的数量。 二、…...

C语言,无法正常释放char*的空间

问题描述 #include <stdio.h> #include <stdio.h>const int STRSIZR 10;int main() {char *str (char *)malloc(STRSIZR*sizeof(char));str "string";printf("%s\n", str);free(str); } 乍一看&#xff0c;这块代码没有什么问题。直接书写…...

重回C语言之老兵重装上阵(十五)C语言错误处理

C语言错误处理 在C语言中&#xff0c;错误处理是非常重要的一部分。C语言没有像高级语言&#xff08;例如Python、Java&#xff09;那样内建的异常处理机制&#xff08;如try-catch&#xff09;&#xff0c;但它提供了几种方法来捕捉和处理错误。正确的错误处理可以提高程序的稳…...

基于微信的课堂助手小程序设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

Effective C++ 规则50:了解 new 和 delete 的合理替换时机

1、背景 在 C 中&#xff0c;new 和 delete 是动态分配内存的核心操作符。然而&#xff0c;直接使用它们有时会增加程序的复杂性&#xff0c;甚至导致内存泄漏和其他问题。因此&#xff0c;了解何时替换 new 和 delete 并选择更适合的内存管理策略&#xff0c;是编写高效、健壮…...

Alfresco Content Services dockerCompose自动化部署详尽操作

Alfresco Content Services docker社区部署文档 Alfresco Content Services简介 Alfresco Content Services&#xff08;简称ACS&#xff09;是一款功能完备的企业内容管理&#xff08;ECM&#xff09;解决方案&#xff0c;主要面向那些对企业级内容管理有高要求的组织。具体…...

学习第七十六行

提高github下载速度方法 1.github转码云 2.https://github.com.cnpmjs.org com后面加东西 对于面试笔试&#xff0c;最好方法刷力扣&#xff0c;1000题包进大厂的...

YOLOv11改进,YOLOv11检测头融合DynamicHead,并添加小目标检测层(四头检测),适合目标检测、分割等任务

摘要 作者提出一种新的检测头,称为“动态头”,旨在将尺度感知、空间感知和任务感知统一在一起。如果我们将骨干网络的输出(即检测头的输入)视为一个三维张量,其维度为级别 空间 通道,这样的统一检测头可以看作是一个注意力学习问题,直观的解决方案是对该张量进行全自…...

一个基于Python+Appium的手机自动化项目~~

本项目通过PythonAppium实现了抖音手机店铺的自动化询价&#xff0c;可以直接输出excel&#xff0c;并带有详细的LOG输出。 1.excel输出效果: 2. LOG效果: 具体文件内容见GitCode&#xff1a; 项目首页 - douyingoods:一个基于Pythonappium的手机自动化项目&#xff0c;实现了…...

【后端开发】字节跳动青训营之性能分析工具pprof

性能分析工具pprof 一、测试程序介绍二、pprof工具安装与使用2.1 pprof工具安装2.2 pprof工具使用 资料链接&#xff1a; 项目代码链接实验指南pprof使用指南 一、测试程序介绍 package mainimport ("log""net/http"_ "net/http/pprof" // 自…...

Linux:线程池和单例模式

一、普通线程池 1.1 线程池概念 线程池&#xff1a;一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价&…...

使用iis服务器模拟本地资源服务器unityaddressables热更新出错记录

editor中设置了using exculexing 模拟远程加载addressable可以实现资源热更新&#xff0c;build后的软件却没有成功。 iis服务器中mime中需要设置bundle的文件扩展名&#xff0c;时editor成功&#xff0c;build后失败 原因没有设置hash的扩展名&#xff0c;设置后editor和buil…...

TikTok广告投放优化策略:提升ROI的核心技巧

在短许多品牌和商家纷纷投入广告营销&#xff0c;争夺这片潜力巨大的市场。然而&#xff0c;在激烈的竞争环境中&#xff0c;如何精准有效地投放广告&#xff0c;优化广告效果&#xff0c;实现更高的投资回报率&#xff08;ROI&#xff09;成为了广告主关注的核心。 一. 精准受…...

能源研究院转让选哪家

能源研究院转让选择建议选择适合的能源研究院转让机构需综合考虑资质、经验、服务范围及行业口碑。以下为关键筛选方向&#xff1a;专业资质与行业经验 优先选择具备国家级资质认证&#xff08;如科技转移服务机构备案&#xff09;的机构&#xff0c;尤其在新能源、储能技术等领…...

PyTorch 2.8镜像开发者案例:独立开发者打造个人AI视频工作室技术栈

PyTorch 2.8镜像开发者案例&#xff1a;独立开发者打造个人AI视频工作室技术栈 1. 从零搭建AI视频工作室的技术选择 作为一名独立开发者&#xff0c;我一直在寻找能够支撑个人AI视频创作的技术方案。经过多次尝试&#xff0c;最终选择了基于PyTorch 2.8的深度学习镜像作为核心…...

intv_ai_mk11真实案例分享:中小企业如何用该模型降本提效做内容生产

intv_ai_mk11真实案例分享&#xff1a;中小企业如何用该模型降本提效做内容生产 1. 中小企业内容生产的痛点与机遇 在当今内容为王的时代&#xff0c;中小企业面临着巨大的内容生产压力。每天需要产出大量文案、产品介绍、营销内容、客服回复等&#xff0c;但往往受限于人力成…...

OpenClaw安全防护指南:Qwen3-14b_int4_awq执行权限管控策略

OpenClaw安全防护指南&#xff1a;Qwen3-14b_int4_awq执行权限管控策略 1. 为什么需要关注OpenClaw的安全防护&#xff1f; 去年冬天&#xff0c;我在调试一个自动整理照片的OpenClaw任务时&#xff0c;不小心让AI误删了整年的旅行照片备份。那一刻我才真正意识到——当AI获得…...

25岁后为什么老得快?你的细胞在偷偷减少

有没有发现一个扎心的事实&#xff1a;25岁像是一道隐形的分水岭&#xff0c;把青春和初老狠狠隔开。20岁的时候&#xff0c;通宵打游戏、追剧、赶ddl&#xff0c;第二天睡半天就能满血复活&#xff0c;脸上看不到一丝疲惫&#xff0c;皮肤透着原生态的光泽&#xff0c;哪怕偶尔…...

从PubMed到知识库:手把手教你用Python把医学文献数据存进MySQL/CSV(含完整代码)

从PubMed到知识库&#xff1a;构建医学文献智能管理系统的Python实战指南 在生物医学研究领域&#xff0c;每天都有数以万计的新文献涌入PubMed数据库。面对如此庞大的知识海洋&#xff0c;研究人员常常陷入两难&#xff1a;如何高效获取目标文献&#xff1f;更重要的是&#x…...

OpenClaw新手入门:千问3.5-9B镜像一键部署与初体验

OpenClaw新手入门&#xff1a;千问3.5-9B镜像一键部署与初体验 1. 为什么选择这个组合&#xff1f; 去年冬天&#xff0c;我第一次在本地尝试用OpenClaw自动整理电脑上的照片。当时对接的是GPT-3.5&#xff0c;每次识别图片内容都要消耗大量token&#xff0c;一个月下来账单让…...

如何设计高质量的API接口:终极完整指南与最佳实践

如何设计高质量的API接口&#xff1a;终极完整指南与最佳实践 【免费下载链接】InterviewGuide &#x1f525;&#x1f525;「InterviewGuide」是阿秀从校园->职场多年计算机自学过程的记录以及学弟学妹们计算机校招&秋招经验总结文章的汇总&#xff0c;包括但不限于C/C…...

MS5611高精度气压温度传感器Arduino驱动库

1. 项目概述MS5611-Mike-Refactored 是一款面向嵌入式平台&#xff08;特别是 Arduino 兼容生态&#xff09;的 MS5611 高精度气压/温度传感器驱动库。该库并非简单封装&#xff0c;而是对 Korneliusz Jarzebski 原始实现的一次系统性重构与工程化增强。其核心目标是将一个基础…...

TimesFM时间序列预测模型实战:从基础模型到高效部署的完整路径

TimesFM时间序列预测模型实战&#xff1a;从基础模型到高效部署的完整路径 【免费下载链接】timesfm TimesFM (Time Series Foundation Model) is a pretrained time-series foundation model developed by Google Research for time-series forecasting. 项目地址: https://…...