SpringBoot框架中提供了2个注解来让开发者快速配置来实现单机定时任务调度的功能。分别是
@EnableScheduling和 @Scheduled
@EnableScheduling注解意思是启用SpringBoot框架的单机定时任务调度的功能,
这个注解要配置到app的启动类上,或者你自定义的@Configuration配置类上,一般都配置到项目的启动类上,方便查找, 如下代码所示
package cn.thinkpet.springbootappscaffold;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling //在启动类上加这个注解,表示开启springboot定时任务功能
@SpringBootApplication
public class SpringbootAppScaffoldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootAppScaffoldApplication.class, args);
}
}
package cn.thinkpet.springbootappscaffold;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class Test1Schedule {
//@Scheduled注解是springboot提供的单机应用的定时任务调度解决方案
//cron是配置定时任务调度的 spring-cron表达式
// spring-cron 一共可以有6个参数 以空格分开
// 注意spring-cron 和quartz的cron不同 ,即 spring-cron不支持配置年份,没有第7个参数,
// 如果需要指定年份的定时任务建议使用quartz,xxl-job,elastic-job这种分布式任务调度框架
// 秒 分 时 日 月 周
//┌───────────── second (0-59)
// │ ┌───────────── minute (0 - 59)
// │ │ ┌───────────── hour (0 - 23)
// │ │ │ ┌───────────── day of the month (1 - 31)
// │ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC)
// │ │ │ │ │ ┌───────────── day of the week (0 - 7)
// │ │ │ │ │ │ (0 or 7 is Sunday, or MON-SUN)
// │ │ │ │ │ │
// * * * * * *
// @Scheduled(cron = "0 41 21 * * ?") // 定点--21点41分0秒 执行
// @Scheduled(cron = "*/1 * * * * ?") //定频--每1秒执行1次
// 0 0 0 ? * MON#1 每月第一个星期一的零点0分0秒
// 0 0 0 ? * 5#2 每月第2个星期五的零点0分0秒
// 0 0 0 L * * 每月最后一天的零点0分0秒
// 0 0 0 * * 5L 每月最后一个星期五的零点0分0秒
//spring-cron表达式 值的常用通配符:
// *:表示所有值 比如用在日 表示每一天。
// ?:表示不指定值 比如周配置 表示不指定星期几执行。
// /:表示递增触发 比如 用在分 5/20 从第五分钟开始 每增加20分钟执行一次。
// -:表示区间 比如用在 1-6 表示一月到六月执行
// # :表示每月中的第几个星期几。5#2:表示每月第2个星期五。MON#1:表示每月第1个星期一
// L :表示最后,比如每月最后一个星期天
//其他通配符可以查询官方文档
//https://docs.spring.io/spring-framework/reference/integration/scheduling.html#scheduling-cron-expression
@Scheduled(cron = "0/1 * * * * ?")
public void singleTaskTest1() throws InterruptedException {
log.info("singleTaskTest1");
}
@Scheduled(cron = "0/1 * * * * ?")
public void singleTaskTest2() throws InterruptedException {
log.info("singleTaskTest2");
}
// @Scheduled(cron = "0/1 * * * * ?")
@Scheduled(cron = "${test3.cron:0/2 * * * * ?}")
//从yml或properties配置文件中读取 cron 值,读不到时使用默认的 0/2 * * * * ?
public void singleTaskTest3() throws InterruptedException {
log.info("singleTaskTest3");
// LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
}
//----------如果嫌配置cron表达式麻烦,可以使用如下的固定速度+固定延期 的方式来配置定时任务-----------
// @Scheduled(initialDelay = 3000,fixedRate = 5000)
//initialDelay表示第一次延迟多少毫秒执行,单位是毫秒
//fixedRate表示多久执行一次,单位是毫秒
@Scheduled(initialDelay = 3000,fixedRate = 5000) //第一次延迟3秒执行,后面间隔5秒执行一次
public void singleTaskTest4() throws InterruptedException {
log.info("singleTaskTest4");
}
}
application.properties文件的配置
server.port=8080
#配置singleTaskTest3的cron表达式
test3.cron=0/7 * * * * ?
在实际开发中,常常会有多个task并发执行的场景,此时为了实现task之间的异步,需要自定义调度器使用的 ThreadPoolTaskScheduler
package cn.thinkpet.springbootappscaffold;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/**
* 为了实现springboot 多个定时任务调度 之间的并发执行,
* 需要重写 调度器使用的 ThreadPoolTaskScheduler
*/
@Configuration
public class MyScheduledConfig implements SchedulingConfigurer {
/**
* 定义springboot定时任务的 --- 线程池大小
*/
private static final int POOL_SIZE = 6;
/**
* 定义springboot定时任务的 ---自定义线程名前缀
*/
private static final String TASK_THREAD_PREFIX = "my-sche-task-";
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//需要创建1个springboot提供的ThreadPoolTaskScheduler
ThreadPoolTaskScheduler bootScheduleExecutor = new ThreadPoolTaskScheduler();
//配置这个springboot项目全部定时任务使用 的线程数是 POOL_SIZE
//在实际应用中需要考虑实际任务数量,创建相应大小的线程池
bootScheduleExecutor.setPoolSize(POOL_SIZE);
//配置线程名前缀
bootScheduleExecutor.setThreadNamePrefix(TASK_THREAD_PREFIX);
//初始化线程池执行器
bootScheduleExecutor.initialize();
//设置 调度器使用 bootScheduleExecutor
taskRegistrar.setTaskScheduler(bootScheduleExecutor);
}
}
2023-06-04 18:17:03.519 INFO 16872 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2023-06-04 18:17:03.519 INFO 16872 --- [ main] o.s.s.c.ThreadPoolTaskScheduler : Initializing ExecutorService
2023-06-04 18:17:03.534 INFO 16872 --- [ main] c.t.s.SpringbootAppScaffoldApplication : Started SpringbootAppScaffoldApplication in 1.506 seconds (JVM running for 2.224)
2023-06-04 18:17:04.007 INFO 16872 --- [ my-sche-task-1] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:04.007 INFO 16872 --- [ my-sche-task-2] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:05.014 INFO 16872 --- [ my-sche-task-3] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:05.014 INFO 16872 --- [ my-sche-task-4] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:06.006 INFO 16872 --- [ my-sche-task-3] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:06.006 INFO 16872 --- [ my-sche-task-6] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:06.541 INFO 16872 --- [ my-sche-task-1] c.t.springbootappscaffold.Test1Schedule : singleTaskTest4
2023-06-04 18:17:07.013 INFO 16872 --- [ my-sche-task-2] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:07.013 INFO 16872 --- [ my-sche-task-4] c.t.springbootappscaffold.Test1Schedule : singleTaskTest3
2023-06-04 18:17:07.013 INFO 16872 --- [ my-sche-task-5] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:08.002 INFO 16872 --- [ my-sche-task-1] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:08.002 INFO 16872 --- [ my-sche-task-2] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:09.009 INFO 16872 --- [ my-sche-task-6] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:09.009 INFO 16872 --- [ my-sche-task-1] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:10.004 INFO 16872 --- [ my-sche-task-1] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:10.004 INFO 16872 --- [ my-sche-task-5] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:11.011 INFO 16872 --- [ my-sche-task-6] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:11.011 INFO 16872 --- [ my-sche-task-5] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:11.545 INFO 16872 --- [ my-sche-task-2] c.t.springbootappscaffold.Test1Schedule : singleTaskTest4
2023-06-04 18:17:12.002 INFO 16872 --- [ my-sche-task-4] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:12.002 INFO 16872 --- [ my-sche-task-3] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:13.009 INFO 16872 --- [ my-sche-task-1] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:13.009 INFO 16872 --- [ my-sche-task-6] c.t.springbootappscaffold.Test1Schedule : singleTaskTest2
2023-06-04 18:17:14.016 INFO 16872 --- [ my-sche-task-2] c.t.springbootappscaffold.Test1Schedule : singleTaskTest1
2023-06-04 18:17:14.016 INFO 16872 --- [ my-sche-task-4] c.t.springbootappscaffold.Test1Schedule : singleTaskTest3