业务场景:需要开启一个定时任务每天执行,任务执行时机通过配置文件获取,但是配置参数不能用cron表达式,要用更容易理解的时间点(时分秒)

首先spring boot开启定时任务,使用@EnableScheduling注解,这个注解写到启动类上或者其他的spring管理的bean上都行

springboot 动态设置fixedDelay_spring

接下来就是编写定时任务了,常用有两种方式,一个是基于注解@Scheduled,另一个是实现接口SchedulingConfigurer

1.基于注解方式

执行定时任务的类一定要被spring管理,可以加@Component注解,然后在方法上加@Scheduled注解就可以了。

package ***.client.task;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class test {

    private static final Logger logger = LoggerFactory.getLogger(SpringDynamicCornTask.class);

    @Scheduled(cron = "0/5 * * * * ?")
    private void test() {
        logger.info("业务处理逻辑。。。5秒一次");
    }


}

执行结果:

springboot 动态设置fixedDelay_定时任务_02

@Scheduled注解有以下几个属性,使用时至少要指定cron,fixedDelay,fixedRat3个属性中的一个。且属性的值支持${}占位符从配置文件获取
例如配置文件加参数:

springboot 动态设置fixedDelay_java_03

占位符获取参数

springboot 动态设置fixedDelay_spring boot_04

这种基于注解的方式很快捷,但是不符合我的需求,虽然可以从配置文件读取参数,但是无法将配置文件中的参数处理翻译为cron表达式。

2.基于接口的方式

创建接口实现类

package ***.client.task;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import ***.client.execute.ExecuteTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

/**
 * 下载报告定时任务
 */
@Component
public class SpringDynamicCornTask implements SchedulingConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(SpringDynamicCornTask.class);

    @Resource
    private ExecuteTask executeTask;

    private static final String DEFAULT_CRON = "00 00 22 * * ?";
    private static String cronMode = "%s %s %s * * ?";
    @Value("${task.cron.time}")
    private String default_cron;


    /**
     * 定时任务配置
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(() -> {
            logger.info("定时任务执行");
            executeTask.run();
        }, triggerContext -> {
            logger.info("配置定时任务下一次触发时间");
            CronTrigger trigger = new CronTrigger(initCron());
            return trigger.nextExecutionTime(triggerContext);
        });
    }


    /**
     * 初始化定时任务cron
     */
    private String initCron() {
        if (!StringUtils.isEmpty(default_cron)) {
            String[] cronArray;
            if (default_cron.contains(":")) {
                cronArray = default_cron.split(":");
            } else if (default_cron.contains(":")) {
                cronArray = default_cron.split(":");
            } else if (NumberUtil.isInteger(default_cron)) {
                String time = DateUtil.secondToTime(Integer.valueOf(default_cron));
                cronArray = time.split(":");
            } else {
                logger.error("定时任务参数读取失败,使用默认参数");
                return DEFAULT_CRON;
            }
            String hour = (cronArray.length > 0 && NumberUtil.isInteger(cronArray[0]) && NumberUtil.parseInt(cronArray[0]) <= 24) ? cronArray[0] : "22";
            String minute = (cronArray.length > 1 && NumberUtil.isInteger(cronArray[0]) && NumberUtil.parseInt(cronArray[0]) <= 60) ? cronArray[1] : "00";
            String second = (cronArray.length > 2 && NumberUtil.isInteger(cronArray[0]) && NumberUtil.parseInt(cronArray[0]) <= 60) ? cronArray[2] : "00";
            String cron = String.format(cronMode, second, minute, hour);
            logger.info("定时任务cron表达式:{}", cron);
            return cron;
        } else {
            logger.error("定时任务参数读取失败,使用默认参数");
            return DEFAULT_CRON;
        }
    }
}

配置文件中的参数:

springboot 动态设置fixedDelay_定时任务_05

我们在实现类中通过自定义的方法来将时分秒翻译为cron表达式,来实现自己的需求。

在实现类中,每次定时任务业务执行完后都会配置触发器下次执行时间,如果我们想要动态控制定时任务的触发时机,在获取下次执行时间的地方改造自己的实现方法,读取数据库或者redis都可以

执行结果:

springboot 动态设置fixedDelay_定时任务_06