相关文章链接
参数详解
@Target({
ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
String CRON_DISABLED = "-";
String cron() default "";
String zone() default "";
long fixedDelay() default -1;
String fixedDelayString() default "";
long fixedRate() default -1;
String fixedRateString() default "";
long initialDelay() default -1;
String initialDelayString() default "";
}
fixedDelay
它的间隔时间是根据上次任务结束的时候开始计时的,只要盯紧上一次任务执行结束的时间即可,跟任务逻辑的执行时间无关,两个任务的间隔时间是固定的
fixedDelayString
与 fixedDalay 一样,不同的是使用的是 String 字符串,支持占位符方式
@Scheduled(fixedDelayString = "${time.fixedDelay}")
public void test() {
System.out.println("Execute at " + System.currentTimeMillis());
}
fixedRate
在理想情况下,下一次开始和上一次开始之间的时间间隔是一定的,但是默认情况下 SpringBoot 定时任务是单线程执行的。当下一轮的任务满足时间策略后任务就会加入队列,即当本次任务开始执行时下一次任务的时间就已经确定了,由于本次任务的“超时”执行,下一次任务的等待时间就会被压缩甚至阻塞
fixedRateString
与 fixedRate 一样,不同的是使用的是 String 字符串,支持占位符方式
initialDelay
这个参数只能配合 fixedDelay 或 fixedRate 使用。如:@Scheduled(initialDelay = 10000, fixedRate = 15000),意思是在容器启动后,延迟 10 秒再执行一次定时器,以后每 15 秒再执行一次该定时器
initialDelayString
与 initialDelay 一样,不同的是使用的是 String 字符串,支持占位符方式
cron 表达式
语法格式:
- 秒 分 小时 月份中的日期 月份 星期中的日期 年份
- 秒 分 小时 月份中的日期 月份 星期中的日期
字段 | 值 | 特殊字符 |
---|---|---|
秒(Seconds) | 0~59 的整数 | , - * / |
分(Minutes) | 0~59 的整数 | , - * / |
小时(Hours) | 0~23 的整数 | , - * / |
日期(DayofMonth) | 1~31 的整数(需要看月的天数) | , - * ? / L W C |
月份(Month) | 1~12 的整数 | , - * / |
星期(DayOfWeek) | 1~7 的整数 | , - * ? / L W C |
年(Year)(可选) | 1970~2099 | , - * / |
-
*:表示匹配该域的任意值。
例如:在 Minutes 域使用*,即表示每分钟都会触发事件
-
?:只能用在 DayofMonth 和 DayofWeek 两个域,它也匹配域的任意值,但实际不会,因为 DayofMonth 和 DayofWeek 会相互影响。
例如:在每月的 20 日触发任务,不管 20 日是星期几,只能使用如下写法:13 13 15 20 * ?,其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发
-
-:表示范围。
例如:在 Minutes 域使用 5-20,表示从 5 到 20 分钟每分钟触发一次
-
/:表示起始时间开始触发,然后每隔固定时间触发一次。
例如:在 Minutes 域使用 5/20,则意味着从第 5 分钟开始,每隔 20 分钟触发一次
-
,:表示列出枚举值。
例如:在 Minutes 域使用 5,20,则意味着在 5 和 20 分都会触发一次
-
L:表示最后,只能出现在 DayofWeek 和 DayofMonth 域。
例如:在 DayofWeek 域使用 5L,意味着在最后的一个星期四触发
-
W:表示有效工作日(周一到周五),只能出现在 DayofMonth 域,系统将在离指定日期的最近的有效工作日触发事件。
例如:在 DayofMonth 使用 5W,如果 5 日是星期六,则将在最近的工作日(星期五,即 4 日触发);如果 5 日是星期天,则在 6 日(星期一)触发;如果 5 日在星期一到星期五中的一天,则就在 5 日触发。注意:W 的最近寻找不会跨过月份
-
LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五
-
#:用于确定每个月第 n 个星期 x(x#n),只能出现在 DayofMonth 域。
例如:4#2 表示第 2 个星期三
常用表达式参考
"*/5 * * * * ?" # 每隔5秒执行一次
"0 */1 * * * ?" # 每隔1分钟执行一次
"0 0 23 * * ?" # 每天23点执行一次
"0 0 1 * * ?" # 每天凌晨1点执行一次
"0 0 1 1 * ?" # 每月1号凌晨1点执行一次
"0 0 23 L * ?" # 每月最后一天23点执行一次
"0 0 1 ? * L" # 每周星期天凌晨1点实行一次:
"0 26,29,33 * * * ?" # 在26分、29分、33分执行一次
"0 0 0,3,8,21 * * ?" # 每天的0点、3点、8点、21点执行一次
"0 0 10,14,16 * * ?" # 每天上午10点,下午2点,4点
"0 0/30 9-17 * * ?" # 朝九晚五工作时间内每半小时
"0 0 12 ? * WED" # 表示每个星期三中午12点
"0 0 12 * * ?" # 每天中午12点触发
"0 15 10 ? * *" # 每天上午10:15触发
"0 15 10 * * ?" # 每天上午10:15触发
"0 15 10 * * ? *" # 每天上午10:15触发
"0 15 10 * * ?" # 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" # 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" # 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" # 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" # 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" # 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" # 周一至周五的上午10:15触发
"0 15 10 15 * ?" # 每月15日上午10:15触发
"0 15 10 L * ?" # 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" # 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" # 每月的第三个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005" # 2002年至2005年的每月的最后一个星期五上午10:15触发
基本使用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
@SpringBootApplication
// 开启定时任务开关
@EnableScheduling
public class SpringtaskApplication {
public static void main(String[] args) {
SpringApplication.run(SpringtaskApplication.class, args);
}
}
@Component
public class TaskService01 {
@Scheduled(fixedDelay = 1000)
public void task01(){
System.out.println("fixedDelay....");
}
@Scheduled(fixedRate = 1000)
public void task02(){
System.out.println("fixedRate....");
}
@Scheduled(initialDelay = 10000,fixedDelay = 1000)
public void task03(){
System.out.println("initialDelay");
}
@Scheduled(cron = "1 * * * * *")
public void task04(){
System.out.println("cron");
}
}
定时任务配置
@EnableScheduling 注解引入了 ScheduledAnnotationBeanPostProcessor 其 setScheduler(Object scheduler) 有以下的注释:
如果 TaskScheduler 或者 ScheduledExecutorService 没有定义为该方法的参数,该方法将在 Spring IoC 中寻找唯一的 TaskScheduler 或者名称为 taskScheduler 的 Bean 作为参数,当然你按照查找 TaskScheduler 的方法找一个 ScheduledExecutorService 也可以。要是都找不到那么只能使用本地单线程调度器了
执行器
SpringBoot 内默认自动配置 TaskExecutor 任务执行器线程池,主要用于执行单次任务
自动配置条件
- 当类路径下存在 ThreadPoolTaskExecutor 类
- 当 Spring 容器中不存在 Executor 的 bean
// 仅在类 ThreadPoolTaskExecutor 存在于 classpath 时才应用
@ConditionalOnClass(ThreadPoolTaskExecutor.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TaskExecutionProperties.class)
public class TaskExecutionAutoConfiguration {
public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor";
@Bean
@ConditionalOnMissingBean
public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties,
ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers,
ObjectProvider<TaskDecorator> taskDecorator) {
TaskExecutionProperties.Pool pool = properties.getPool();
TaskExecutorBuilder builder = new TaskExecutorBuilder();
builder = builder.queueCapacity(pool.getQueueCapacity());
builder = builder.corePoolSize