SpringBoot 实现定时任务的两种方式:基于注解(@Scheduled)的简单定时器,基于接口SchedulingConfigurer的动态定时任务


一、cron表达式语法

cron表达式语法:[秒] [分] [小时] [日] [月] [周] [年]

序号说明是否必填允许填写的值允许的通配符
10-59, - * /
20-59, - * /
3小时0-23, - * /
41-31, - * ? / L W
51-12 or JAN-DEC, - * /
61-7 or SUN-SAT, - * ? / L #
7empty 或 1970-2099, - * /

常用通配符说明:

  1. 反斜线(/)字符表示增量值。例如,在秒字段中“5/15”代表从第 5 秒开始,每 15 秒一次。
  2. 星号()字符是通配字符,表示该字段可以接受任何可能的值(例如:在分的字段上设置 "",表示每一分钟都会触发)。
  3. 问号(?)问号表示这个字段不包含具体值。所以,如果指定月内日期,可以在月内日期字段中插入“?”,表示周内日期值无关紧要。字母 L 字符是 last 的缩写。放在月内日期字段中,表示安排在当月最后一天执行。在周内日期字段中,如果“L”单独存在,就等于“7”,否则代表当月内周内日期的最后一个实例。所以“0L”表示安排在当月的最后一个星期日执行。
  4. 横杠(-) 表示区间,例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。
  5. 逗号(, ) 表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发
  6. 井号(#)字符为给定月份指定具体的工作日实例。把“MON#2”放在周内日期字段中,表示把任务安排在当月的第二个星期一。

二、Scheduled注解使用

@Scheduled(fixedDelay = 5000) //上一次执行完毕时间点之后5秒再执行
@Scheduled(fixedDelayString = “5000”) //上一次执行完毕时间点之后5秒再执行
@Scheduled(fixedRate = 5000) //上一次开始执行时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次

1、代码

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.time.LocalDateTime;

/**
 * @author lichangyuan
 * @create 2021-12-14 15:11
 */

//1.主要用于标记配置类
@Configuration
// 2.开启定时任务
@EnableScheduling
public class MySchedule {
    //3.添加定时任务
    @Scheduled(cron = "0/5 * * * * ?")
    //或直接指定时间间隔,例如:5秒
    //@Scheduled(fixedRate=5000)
    private void configureTasks() {
        System.err.println("基于注解(@Scheduled)的简单定时器demo: " + LocalDateTime.now());
    }
}

2、效果

在这里插入图片描述

三、SchedulingConfigurer接口

这里核心的主要是使用到了ScheduledTaskRegistrar这个类有一个方法addTriggerTask(Runnable,Trigger) 两个参数,一个Runnable,一个是Trigger,在Runnable中执行业务逻辑代码,在Trigger修改定时任务的执行周期。

1、代码

//1.主要用于标记配置类
@Configuration
// 2.开启定时任务
@EnableScheduling
public class MySchedulingConfigurer implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //创建一个线程作为任务
        taskRegistrar.addTriggerTask(new Runnable() {
            @Override
            public void run() {
                System.err.println("基于接口(SchedulingConfigurer)的简单定时器demo: " + LocalDateTime.now());
            }
            //创建周期
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                String cron = "0/6 * * * * ?";
                CronTrigger trigger = new CronTrigger(cron);
                return trigger.nextExecutionTime(triggerContext);
            }
        });
    }
}

2、效果

在这里插入图片描述

四、进阶版基于接口SchedulingConfigurer的动态定时任务

1、代码

配置文件application.yml内容

#设置定时任务
#是否开启定时任务1
task.taskName1.switch=true
#任务表达式
task.taskName1.cron=0/5 * * * * ?

#是否开启定时任务2
task.taskName2.switch=true
#任务表达式
task.taskName2.cron=0/6 * * * * ?

配置类

/**
 * @author lichangyuan
 * @create 2021-12-14 15:47
 */
@Configuration
@EnableScheduling
public abstract class MySchedulingConfigurer2 implements SchedulingConfigurer {
    /**
     * @brief 定时任务周期表达式
     */
    private String cron;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        //设置的线程池corePoolSize,自己根据业务需求设定
        scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));

        scheduledTaskRegistrar.addTriggerTask(
                //执行定时任务(Lambda 表达式)
                () -> {
                    processTask();
                },
                //设置触发器(Lambda 表达式)
                triggerContext -> {
                    // 初始化定时任务周期
                    if (StringUtils.isEmpty(cron)) {
                        cron = getCron();
                    }
                    CronTrigger trigger = new CronTrigger(cron);
                    return trigger.nextExecutionTime(triggerContext);
                }
        );
    }


    /**
     * @brief 任务的处理函数
     * 本函数需要由派生类根据业务逻辑来实现
     */
    protected abstract void processTask();


    /**
     * @return String
     * @brief 获取定时任务周期表达式
     * 本函数由派生类实现,从配置文件,数据库等方式获取参数值
     */
    protected abstract String getCron();

}

实现类1

/**
 * @author lichangyuan
 * @create 2021-12-14 15:47
 */
@Configuration
public class MySchedulingController1 extends MySchedulingConfigurer2 {

    @Value(value = "${task.taskName1.switch}")
    private Boolean isSwitch;

    @Value(value = "${task.taskName1.cron}")
    private String cron;

    @Override
    protected void processTask() {
        if (isSwitch){
            System.err.println("MySchedulingController1类基于接口(SchedulingConfigurer)的简单定时器demo: " + LocalDateTime.now());
        }

    }

    @Override
    protected String getCron() {
        return cron;
    }
}

实现类2

/**
 * @author lichangyuan
 * @create 2021-12-14 15:47
 */
@Configuration
public class MySchedulingController2 extends MySchedulingConfigurer2 {
    @Value(value = "${task.taskName2.switch}")
    private Boolean isSwitch;

    @Value(value = "${task.taskName2.cron}")
    private String cron;


    @Override
    protected void processTask() {
        if (isSwitch){
            System.err.println("MySchedulingController2类基于接口(SchedulingConfigurer)的简单定时器demo: " + LocalDateTime.now());
        }

    }

    @Override
    protected String getCron() {
        return cron;
    }

}

2、效果

在这里插入图片描述

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

和烨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值