在日常java开发中,定时任务是高频需求场景,比如定时同步数据、定时清理日志、定时发送通知等。spring框架提供的@scheduled注解简化了定时任务的开发,无需依赖外部调度框架(如quartz),就能快速实现轻量级定时任务。而cron表达式作为schedule中灵活度最高的触发规则配置方式,是掌握该功能的核心。本文将从schedule的基础用法入手,深入解析cron表达式,并结合实例演示其在项目中的应用。
一、spring schedule基础配置
要使用spring schedule,首先需要完成基础配置,整体步骤简单易懂,适用于spring boot项目和传统spring项目。
1.1 依赖引入(spring boot)
spring boot项目无需额外引入依赖,spring-boot-starter中已包含schedule相关组件,只需确保pom.xml(maven)中存在核心依赖:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter</artifactid>
</dependency>1.2 开启定时任务支持
在spring boot启动类上添加@enablescheduling注解,开启定时任务调度功能:
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.scheduling.annotation.enablescheduling;
@springbootapplication
@enablescheduling // 开启定时任务
public class scheduledemoapplication {
public static void main(string[] args) {
springapplication.run(scheduledemoapplication.class, args);
}
}1.3 基础定时任务实现
通过@scheduled注解标记方法为定时任务,支持多种触发规则,常见的有固定延迟、固定频率和cron表达式三种方式。其中cron表达式适用于复杂的时间规则配置,也是本文重点。
import org.springframework.scheduling.annotation.scheduled;
import org.springframework.stereotype.component;
@component // 交给spring管理
public class scheduletask {
// 固定延迟:上一次任务执行完毕后延迟1秒执行下一次
@scheduled(fixeddelay = 1000)
public void fixeddelaytask() {
system.out.println("固定延迟任务执行:" + system.currenttimemillis());
}
// 固定频率:每隔1秒执行一次(无论上一次是否完成)
@scheduled(fixedrate = 1000)
public void fixedratetask() {
system.out.println("固定频率任务执行:" + system.currenttimemillis());
}
// cron表达式:每天凌晨2点执行
@scheduled(cron = "0 0 2 * * ?")
public void crontask() {
system.out.println("cron任务执行:" + system.currenttimemillis());
}
}二、cron表达式深度解析
cron表达式是一种时间表达式,用于定义复杂的定时规则,起源于unix系统,后被广泛应用于各类调度框架。在spring schedule中,cron表达式支持6个或7个字段,字段之间用空格分隔,语法格式如下:
2.1 表达式格式
spring schedule中的cron表达式格式(7个字段,最后一个年份字段可选):
秒 分 时 日 月 周 年(可选)
各字段的取值范围及允许的特殊字符如下表所示:
字段 | 取值范围 | 允许的特殊字符 | 说明 |
|---|---|---|---|
秒 | 0-59 | , - * / | 每秒用*表示,每5秒用0/5表示 |
分 | 0-59 | , - * / | 每分用*表示,每10分用0/10表示 |
时 | 0-23 | , - * / | 每天凌晨2点用2表示,每6小时用0/6表示 |
日 | 1-31 | , - * / ? l w c | ?表示不指定值,避免日和周冲突;l表示当月最后一天 |
月 | 1-12 或 jan-dec | , - * / | 1表示1月,jan也可表示1月 |
周 | 1-7 或 sun-sat | , - * / ? l c # | 1表示周日,7表示周六;#表示第几个周几,如6#3表示当月第3个周五 |
年(可选) | 1970-2099 | , - * / | 省略时表示所有年份 |
2.2 特殊字符含义
cron表达式的灵活度依赖于特殊字符的使用,核心特殊字符的含义如下:
- *:表示匹配该字段的所有值。例如,时字段为*,表示每小时都触发。
- ?:仅用于日和周字段,标识不指定具体值,避免两个字段冲突。例如,要指定每月10号触发,周字段需设为?
- /:表示递增触发。格式为“起始值/步长”,例如,秒字段为0/5,表示从0秒开始,每5秒触发一次。
- -:表示区间。例如,时字段为9-17,表示上午9点到下午5点之间,每小时触发一次。
- ,:表示多个值。例如,分字段为10,20,30,表示每小时的10分、20分、30分各触发一次。
- l:仅用于日和周字段,标识最后一个。例如,日字段为l,表示当月最后一天;周字段为l,表示当月最后一个周六。
- #:仅用于周字段,标识第几个周几。格式为“周几#第几个”,例如,周字段为6#3,表示当月第3个周五(6表示周五)。
2.3 常用cron表达式示例
结合实际业务场景,整理以下常用cron表达式,可直接套用:
- 0 0 2 * * ?:每天凌晨2点执行
- 0 30 8 * * ?:每天早上8点30分执行
- 0 0/10 * * * ?:每10分钟执行一次
- 0 0 9-18 * * ?:每天上午9点到下午6点,每小时执行一次
- 0 0 12 ? * sat:每周六中午12点执行
- 0 0 0 l * ?:每月最后一天凌晨0点执行
- 0 0 0 1 * ?:每月1号凌晨0点执行
- 0 0 0 ? * 6#1:每月第一个周五凌晨0点执行
- 0/5 * * * * ?:每5秒执行一次(用于测试)
三、schedule进阶用法与注意事项
3.1 异步定时任务
默认情况下,spring schedule的定时任务是同步执行的,即多个任务会在同一个线程中按顺序执行,若某个任务执行时间过长,会阻塞其他任务。如需异步执行,可通过@enableasync和@async注解实现:
// 1. 启动类添加@enableasync开启异步支持
@springbootapplication
@enablescheduling
@enableasync
public class scheduledemoapplication { ... }
// 2. 定时任务方法添加@async注解
@component
public class scheduletask {
@async
@scheduled(cron = "0/5 * * * * ?")
public void asynccrontask() {
system.out.println("异步cron任务执行:" + thread.currentthread().getname());
}
}3.2 动态调整cron表达式
静态cron表达式在项目启动后无法修改,若需动态调整触发规则,可通过实现schedulingconfigurer接口自定义调度配置,从数据库或配置中心读取cron表达式:
import org.springframework.scheduling.annotation.schedulingconfigurer;
import org.springframework.scheduling.config.scheduledtaskregistrar;
import org.springframework.scheduling.support.crontrigger;
import org.springframework.stereotype.component;
@component
public class dynamiccrontask implements schedulingconfigurer {
// 模拟从数据库获取cron表达式(实际项目中可对接db或nacos)
private string cron = "0/5 * * * * ?";
@override
public void configuretasks(scheduledtaskregistrar taskregistrar) {
// 注册定时任务
taskregistrar.addtriggertask(
this::dynamictaskexecute, // 任务执行逻辑
triggercontext -> {
// 每次触发前重新获取cron表达式(实现动态更新)
crontrigger trigger = new crontrigger(getcron());
return trigger.nextexecutiontime(triggercontext);
}
);
}
public void dynamictaskexecute() {
system.out.println("动态cron任务执行:" + system.currenttimemillis());
}
// 获取最新cron表达式(可扩展为从数据库查询)
public string getcron() {
return this.cron;
}
// 更新cron表达式
public void setcron(string cron) {
this.cron = cron;
}
}3.3 核心注意事项
- 日和周字段冲突:日和周字段不能同时指定具体值,需有一个设为?,否则会导致任务触发规则异常。例如,要指定每月10号执行,周字段必须设为?,表达式为0 0 0 10 * ?。
- 任务执行时长:同步任务中,若任务执行时长超过触发间隔,下一次任务会等待上一次完成后再执行;异步任务无此限制,但需注意并发问题。
- 时区问题:spring schedule默认使用服务器时区,若需指定时区,可在
@scheduled注解中设置zone属性,例如zone = "gmt+8"。 - 避免耗时操作:定时任务中应避免执行耗时过长的操作,建议将耗时逻辑异步处理,或拆分任务,防止阻塞调度线程。
到此这篇关于java定时任务schedule的基本用法及cron表达式实践的文章就介绍到这了,更多相关java schedule用法内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论