SpringBoot 定时任务

基于注解,静态执行周期

Spring Task 是 Spring 提供的轻量级定时任务工具,相比于其他第三方类库更加方便易用。

  1. 新建配置类,添加@EnableScheduling注解开启SpringTask。

@Configuration
@EnableScheduling
public class SpringTaskConfiguration {
}
  1. 创建定时任务类,使用@Scheduled注解注册Cron表达式执行定时任务。

@Slf4j
@Component
public class CronTask {
    @Scheduled(cron = "0/1 * * ? * ?")
    public void cron() {
        log.info("cron:{}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
}

默认情况下,@Scheduled创建的线程池大小为1,如果想增加线程池大小的话,可以让SpringTaskConfiguration类实现SchedulingConfigurer接口,通过setPoolSize增加线程池大小。

@Configuration
@EnableScheduling
public class SpringTaskConfiguration implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        var threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10);  // 设置线程池线程数量
        threadPoolTaskScheduler.setThreadNamePrefix("task-");  // 设置线程名称前缀
        threadPoolTaskScheduler.initialize();  // 初始化线程池
        taskRegistrar.setScheduler(threadPoolTaskScheduler);
    }
}

Spring Task 除了支持Cron表达式,还有fixedRate(固定速率执行)、fixedDelay(固定延迟执行)、initialDelay(初始延迟)三种用法。

// 固定速率执行。每5秒执行一次。
@Scheduled(fixedRate = 5000)
public void reportCurrentTimeWithFixedRate() {
    log.info("Current Thread : {}", Thread.currentThread().getName());
    log.info("Fixed Rate Task : The time is now {}", DateUtil.now());
}

动态设置执行周期(基于接口)

使用@Scheduled注解很方便,但缺点是当调整了执行周期后,需要重新打包部署才能生效,为了省去这一步,我们可以将执行周期存在数据库或者相关的配置文件中,服务可以从数据库或者配置中读取。

@Configuration
@EnableScheduling
public class SpringTaskConfiguration implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(() -> {
            // 任务逻辑
            System.out.println("执行定时任务");
        }, triggerContext -> {
            // 此处的cron表达式可以从数据库或配置文件中读取,方便实现定时任务的动态配置
            String cron = "0/5 * * * * ?";
            CronTrigger cronTrigger = new CronTrigger(cron);
            return cronTrigger.nextExecution(triggerContext);
        });
    }
}

多线程定时任务

@Component
@EnableAsync
public class CornTask {
    @Async
    @Scheduled(fixedDelay = 1000)  //间隔1秒
    public void first() throws InterruptedException {
        System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
        Thread.sleep(1000 * 10);
    }

    @Async
    @Scheduled(fixedDelay = 2000)
    public void second() {
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }
}

Corn 表达式

Cron表达式是一个含有时间意义的字符串,以5个空格隔开,分成6个时间元素。例如:

示例
说明

0 15 10 ? * *

每天上午10:15执行任务

0 0 10,14,16 * * ?

每天10 点、14 点、16 点执行任务

0 0 12 ? * 3

每个星期三中午 12 点执行任务

0 15 10 15 * ?

每月 15 日上午 10 点 15 执行任务

每个时间元素的取值范围,以及可出现的特殊字符如下所示。

时间元素
取值范围
可出现的特殊字符

[0,59]

*,-/

分钟

[0,59]

*,-/

小时

[0,59]

*,-/

日期

[0,31]

*,-/?LW

月份

[1,12]

*,-/

星期

[1,7]

*,-/?L#

特殊字符的含义和示例如下所示。

特殊字符
含义
示例

*

所有可能的值

很好理解,月域中为每个月,星期域中每个星期几

,

枚举的值

很好理解,小时域中 10,14,16,就表示这几个小时可选

-

范围

很好理解,分钟域中 10-19,就表示 10-19 分钟每隔一分钟执行一次

/

指定数值的增量

很好理解,分钟域中 0/15,就表示每隔 15 分钟执行一次

?

不指定值

很好理解,日期域指定了星期域就不能指定值,反之亦然,因为日期域和星期域属于冲突关系

L

单词 Last 的首字母

很好理解,日期域和星期域支持,表示月的最后一天或者星期的最后一天

W

除周末以外的工作日

很好理解,仅日期域支持

#

每个月的第几个星期几

很好理解,仅星期域支持,4#2表示某月的第二个星期四

最后更新于

这有帮助吗?