SpringBoot的@Scheduled和@Schedules有什么区别

@Scheduled 的详细解析

参数详解
  • cron: 使用Cron表达式来指定复杂的调度模式。Cron表达式的格式如下:

    • 秒(0-59)
    • 分钟(0-59)
    • 小时(0-23)
    • 日(1-31)
    • 月(1-12 或 JAN-DEC)
    • 星期(0-7 或 SUN-SAT,其中0和7都表示星期日)
    • 年(可选,1970-2099)

    Cron表达式的每个字段可以是具体的值、范围、列表或通配符(*)。例如:

    • "0 0 12 * * ?" 表示每天中午12点。
    • "0 15 10 ? * MON-FRI" 表示周一至周五上午10:15执行。
    • "0 0/5 * * * ?" 表示每5分钟执行一次。
    • "0 0 12 1 * ?" 表示每月第一天中午12点执行。
  • fixedRate: 指定以固定的速率重复执行任务,从前一次任务开始时刻算起。它不会等待前一个任务完成,因此如果任务执行时间超过了设定的时间间隔,可能会有重叠的任务实例在运行。

  • fixedDelay: 类似于 fixedRate,但是它是以前一次任务的完成时刻作为下一次任务启动的时间基准。这种方式可以确保每次只有一个任务实例在运行,前提是任务的执行时间短于延迟时间。

  • initialDelay: 在第一次执行之前等待的时间(毫秒)。这个参数通常与 fixedRatefixedDelay 一起使用,用来设置首次执行前的延迟。

  • zone: 定义时区,默认是系统的默认时区。如果你的应用需要在全球不同地区运行,明确指定时区可能是很重要的。

示例代码
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class ScheduledTasks {// 每天中午12点执行(上海时区)@Scheduled(cron = "0 0 12 * * ?", zone = "Asia/Shanghai")public void scheduledTaskUsingCron() {System.out.println("Scheduled task using cron at Asia/Shanghai timezone.");}// 每5秒执行一次,首次执行前等待2秒@Scheduled(fixedRate = 5000, initialDelay = 2000)public void scheduledTaskWithFixedRate() {System.out.println("Scheduled task with fixed rate.");}// 上次任务完成后等待3秒再执行下一次@Scheduled(fixedDelay = 3000)public void scheduledTaskWithFixedDelay() {System.out.println("Scheduled task with fixed delay.");}
}

@Schedules 的详细解析

@Schedules 允许多个 @Scheduled 注解组合在一起,为同一个方法设定多种不同的调度策略。这对于那些需要在多个不同时间点或条件下触发的方法非常有用。

示例代码
import org.springframework.scheduling.annotation.Schedules;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class MultipleScheduledTasks {// 每天中午12点执行,并且每5秒也执行一次@Schedules({@Scheduled(cron = "0 0 12 * * ?"),@Scheduled(fixedRate = 5000)})public void multipleScheduledTasks() {System.out.println("Multiple scheduled tasks.");}
}

启用和管理定时任务

要使这些注解生效,你需要确保你的Spring应用已经启用了对它们的支持。这可以通过在配置类上添加 @EnableScheduling 来实现:

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;@Configuration
@EnableScheduling
public class SchedulingConfig {// 配置类内容
}

自定义 TaskScheduler

对于更复杂的需求,比如调整线程池大小或者设置线程名称前缀等,你可以通过自定义 TaskScheduler 来进行配置。Spring提供了几种内置的调度器实现,如 ThreadPoolTaskSchedulerConcurrentTaskScheduler

示例代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
public class SchedulerConfig {@Beanpublic ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setPoolSize(10); // 设置线程池大小taskScheduler.setThreadNamePrefix("MyScheduledTask-");taskScheduler.setErrorHandler(t -> {System.err.println("Error occurred in scheduled task: " + t.getMessage());});taskScheduler.setWaitForTasksToCompleteOnShutdown(true);taskScheduler.setAwaitTerminationSeconds(60);return taskScheduler;}
}

错误处理

当一个预定任务抛出异常时,默认情况下Spring会记录错误日志,但任务本身不会被取消。如果你想改变这种行为,可以使用 DelegatingErrorHandlingRunnable 或者直接在 ThreadPoolTaskScheduler 中设置错误处理器(如上面的示例所示)。

自定义错误处理逻辑

你可以创建自己的错误处理器来捕获并处理异常:

import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
public class AsyncConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(2);executor.setMaxPoolSize(5);executor.setQueueCapacity(100);executor.setThreadNamePrefix("Async-");executor.initialize();return executor;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return new SimpleAsyncUncaughtExceptionHandler() {@Overridepublic void handleUncaughtException(Throwable ex, Method method, Object... params) {// 自定义异常处理逻辑System.err.println("Exception in async task: " + ex.getMessage());}};}
}

最佳实践

  • 避免长时间运行的任务:尽量不要让预定任务执行过长的时间,因为它们可能会阻塞其他任务的执行。如果任务有可能运行很长时间,请考虑将其拆分为更小的部分,或者使用异步处理。

  • 任务冲突管理:当使用 fixedRate 时,要注意任务可能会重叠。如果任务执行时间可能超过间隔时间,应该选择 fixedDelay 来避免这种情况。

  • 资源清理:确保在任务结束时正确释放任何获取的资源,比如数据库连接或文件句柄。

  • 监控和报警:建立适当的监控和报警机制,以便在任务失败时能够及时收到通知并采取行动。可以利用Spring Boot Actuator提供的健康检查端点,或者集成第三方监控工具如Prometheus、Grafana等。

  • 幂等性设计:确保任务逻辑具有幂等性,即多次执行相同的任务不会导致不一致的结果。这在分布式环境中尤为重要。

  • 日志记录:为每个任务添加详细的日志记录,包括任务开始时间和结束时间,以便追踪任务执行情况。

  • 测试:编写单元测试和集成测试来验证定时任务的行为是否符合预期。可以使用Mockito或其他测试框架模拟依赖服务。

  • 多实例部署的问题:在多实例部署的情况下,所有的实例都会尝试执行相同的定时任务,这可能导致数据竞争或重复执行。一种解决方案是使用分布式锁,如Redisson提供的RedLock,来保证同一时间只有一个实例执行特定的任务。

  • 性能优化:对于高并发场景下的定时任务,应该评估线程池的大小和任务的执行频率,避免因过多的任务同时启动而导致资源耗尽。可以通过限流、队列管理和异步处理等方式提高系统的稳定性和响应速度。

处理定时任务中的常见问题

  • 任务未按预期执行:检查日志以确定是否有任何异常或错误信息。确保任务方法是非静态的,并且没有被final修饰。确认 @EnableScheduling 已经正确启用。另外,检查是否存在其他因素阻止任务执行,如网络延迟或依赖服务不可用。

  • 任务执行顺序混乱:如果你有多个任务几乎同时执行,可能会出现执行顺序混乱的情况。确保你理解了 fixedRatefixedDelay 的区别,并根据需要选择合适的方式。此外,可以通过增加任务之间的最小间隔时间来减少冲突的可能性。

  • 多实例部署的问题:在多实例部署的情况下,所有实例都会尝试执行相同的定时任务。为了解决这个问题,可以引入分布式锁机制,如基于Redis的锁或Zookeeper的临时节点,以确保同一时间只有一个实例执行任务。

  • 长时间运行的任务:尽量不要让预定任务执行过长的时间,因为它们可能会阻塞其他任务的执行。如果任务有可能运行很长时间,请考虑将其拆分为更小的部分,或者使用异步处理,如通过消息队列(MQ)来分发任务。

  • 时区问题:确保你的应用程序正确处理时区差异,特别是在全球范围内运行时。可以在 @Scheduled 注解中显式指定 zone 参数,或者在整个应用程序中统一配置默认时区。

案例分析

假设你正在开发一个电子商务平台,需要每天凌晨2点生成前一天的销售报告。你可以使用 @Scheduled 注解来安排这个任务:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;@Service
public class DailyReportService {@Scheduled(cron = "0 0 2 * * ?", zone = "Asia/Shanghai")public void generateDailySalesReport() {// 执行生成销售报告的逻辑System.out.println("Generating daily sales report at Asia/Shanghai timezone.");}
}

此外,你还可以结合上述的最佳实践来增强任务的可靠性,例如:

  • 确保任务具有幂等性,即使由于某种原因任务重复执行也不会影响结果。
  • 添加详细的日志记录,帮助追踪任务的执行情况。
  • 实现错误处理逻辑,确保即使发生异常也能得到妥善处理。
  • 如果平台有多实例部署,考虑使用分布式锁来防止多个实例同时生成报告。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/66924.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js基础---书写位置

js基础—书写位置 内部 直接写在html文件里面&#xff0c;用script标签包住 规范 &#xff1a;script 标签写在上面 代码演示 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport"…

SpringBoot操作spark处理hdfs文件

SpringBoot操作spark处理hdfs文件 1、导入依赖 <!-- spark依赖--><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.12</artifactId><version>3.2.2</version></dependency><depend…

Jaeger UI使用、采集应用API排除特定路径

Jaeger使用 注&#xff1a; Jaeger服务端版本为&#xff1a;jaegertracing/all-in-one-1.6.0 OpenTracing版本为&#xff1a;0.33.0&#xff0c;最后一个版本&#xff0c;停留在May 06, 2019。最好升级到OpenTelemetry。 Jaeger客户端版本为&#xff1a;jaeger-client-1.3.2。…

PySide6-UI界面设计

导论&#xff1a; PySide6和PyQt都是Python对Qt框架的绑定&#xff0c;允许开发者使用Qt创建平台的GUI应用程序。如果你正在开发商业项目&#xff0c;或者需要使用最新的QT6特性&#xff0c;PySide6是一个更好的选择。如果你更倾向于一个成熟的社区和丰富的资源&#xff0c;Py…

使用 Multer 上传图片到阿里云 OSS

文件上传到哪里更好&#xff1f; 上传到服务器本地 上传到服务器本地&#xff0c;这种方法在现今商业项目中&#xff0c;几乎已经见不到了。因为服务器带宽&#xff0c;磁盘 IO 都是非常有限的。将文件上传和读取放在自己服务器上&#xff0c;并不是明智的选择。 上传到云储存…

电机控制的数字化升级:基于DSP和FPGA的仿真与实现

数字信号处理器&#xff08;DSP&#xff0c;Digital Signal Processor&#xff09;在工业自动化领域的应用日益广泛。DSP是一种专门用于将模拟信号转换成数字信号并进行处理的技术&#xff0c;能够实现信号的数字滤波、重构、调制和解调等多项功能&#xff0c;确保信号处理的精…

微服务的CAP定理与数据一致性抉择

分布式系统中的CAP定理&#xff0c;包括一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition Tolerance&#xff09;三个核心要素。 微服务是分布式系统的一种表现形式&#xff0c;以及用户对于系统是分…

leetcode_2816. 翻倍以链表形式表示的数字

2816. 翻倍以链表形式表示的数字 - 力扣&#xff08;LeetCode&#xff09; 搜先看到这个题目 链表的节点那么多 已经远超longlong能够表示的范围 那么暴力解题 肯定是不可以的了 我们可以想到 乘法运算中 就是从低位到高位进行计算 刚开始 我想先反转链表 然后在计算 然后在进…

Element Plus 之 el-table相同行合并(通用函数),相同列合并(自行判断需合并的字段以及相应的列下标)

展示 代码 <el-table :data"tableData" border style"width: 100%" :span-method"objectSpanMethod"><el-table-column prop"date" label"Date" width"180" align"center" /><el-table…

QT中引入OpenCV库总结(qmake方式和cmake方式)

文章目录 前言opencv环境配置一、opencv库获取的两种方式二、qmake和cmake配置2.1、 qmake2.2、cmake2.2.1、引入opencv示例 三、qt与opencv对应关系四、问题 前言 我的软件环境&#xff0c;写在前面 Windows10QT5.12.12VS2017OpenCV4.5.4 opencv环境配置 一、opencv库获取…

[石榴翻译] 维吾尔语音识别 + TTS语音合成

API网址 丝路AI平台 获取 Access token 接口地址&#xff1a;https://open.xjguoyu.cn/api/auth/oauth/token&#xff0c;请求方式&#xff1a;GET&#xff0c;POST Access token是调用服务API的凭证&#xff0c;调用服务API之前需要获取 token。每次成功获取 token 以后只有…

webrtc之rtc::ArrayView<const uint8_t>

rtc::ArrayView<const uint8_t> 是 WebRTC&#xff08;或其他基于 rtc 命名空间的库&#xff09;中常见的一个类型&#xff0c;它通常用于表示一块 只读的内存区域&#xff0c;该内存区域由一系列 uint8_t 类型&#xff08;无符号 8 位整数&#xff09;元素组成。 1. rt…

汽车供应链关键节点:物流采购成本管理全解析

在汽车行业&#xff0c;供应链管理是一项至关重要的任务。汽车制造从零部件的生产到整车的交付&#xff0c;涉及多个环节&#xff0c;其中物流、采购与成本管理是核心节点。本文将深入分析这些关键环节&#xff0c;探讨如何通过供应商管理系统及相关工具优化供应链管理。 一、…

Linux文件系统的安全保障---Overlayroot!

overlayroot 是一种使用 OverlayFS 实现的功能&#xff0c;可将根文件系统挂载为只读&#xff0c;并通过一个临时的写层实现对文件系统的修改。这种方法非常适合嵌入式设备或需要保持系统文件完整性和安全性的场景。下文以 RK3568 平台为例&#xff0c;介绍制作 overlayroot 的…

DEVIN AI==初步使用

注册 官网 Devin (the Developer) 开启一个对话session 体验第一个官方DEMO 工作内容是爬取两个网页&#xff0c;对比他们的注册流程&#xff0c;然后生成一个网页展示对比的结果 左边是对话&#xff0c;可以描述你的需求&#xff0c;右边是DEVIN根据你的要求做的一些事情&…

【Rust自学】11.3. 自定义错误信息

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 11.3.1. 添加错误信息 在 11.2. 断言(Assert) 中我们学习了assert!、assert_eq!和assert_ne!这三个宏&#xff0c;而这篇文章讲的就是它…

git - 用SSH方式迁出远端git库

文章目录 git - 用SSH方式迁出远端git库概述笔记以gitee为例产生RSA密钥对 备注END git - 用SSH方式迁出远端git库 概述 最近一段时间&#xff0c;在网络没问题的情况下&#xff0c;用git方式直接迁出git库总是会失败。 失败都是在远端, 显示RPC错误。 但是git服务器端是没问…

Linux第一个系统程序---进度条

进度条---命令行版本 回车换行 其实本质上回车和换行是不同概念&#xff0c;我们用一张图来简单的理解一下&#xff1a; 在计算机语言当中&#xff1a; 换行符&#xff1a;\n 回车符&#xff1a;\r \r\n&#xff1a;回车换行 这时候有人可能会有疑问&#xff1a;我在学习C…

智慧城市应急指挥中心系统平台建设方案

建设背景与目标 智慧城市应急指挥中心系统平台的建设&#xff0c;源于对城市管理精细化、智能化的迫切需求。平台旨在通过整合各方资源&#xff0c;实现应急事件的快速响应与高效处置&#xff0c;提升城市安全管理水平。 前端设计与信息采集 前端设计注重立体化、全方位信息…

011:利用大津算法完成图片分割

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 上一篇文章介绍了大津算法可以完成图片的前景和背景分割。 总的来说&#xff0c;大津算法的核心思想就两个&#xff1a; 数学上&#xff0c;通过确定一个像素阈值&#xf…