springboot定时任务机制

定时任务

简单定时任务

springboot使用简单定时任务,非常简单。
三步:
1、@Configuration
标记本类为配置类
2、@EnableScheduling
表示开启springboot的定时任务模块
3、@Scheduled(cron = "0/5 * * * * ?")
通过cron表达式控制执行时间

//1.主要用于标记配置类
@Configuration
// 2.开启定时任务
@EnableScheduling
@Slf4j
public class Schedule {
    //3.添加定时任务
    @Scheduled(cron = "0/5 * * * * ?")
    //或直接指定时间间隔,例如:5秒
    //@Scheduled(fixedRate=5000)
    private void configureTasks() throws InterruptedException {

        log.info("基于注解(@Scheduled)的简单定时器demo: " + LocalDateTime.now());
        TimeUnit.SECONDS.sleep(6);
    }

    @Scheduled(cron = "* * * * * ?")
    private void configureTasks1() {
        log.error("基于注解(@Scheduled): " + LocalDateTime.now());
    }
}

缺点
1、无法修改Scheduled里面cron的值,一旦在代码里写死,启动后就无法修改。
2、如果没有做其他配置,则在spring环境中默认只会有一个子线程来执行所有的定时任务。

可能会出现上一个定时任务的执行时间过长,影响下一个定时任务的执行。
在上述代码中,两个定时任务都是 scheduling-1这个线程来执行的。

动态多线程定时任务

采用这种方式配置定时任务的好处主要有以下几点:
1、多线程执行定时任务,所以定时任务之间不会相互影响
2、可以动态修改cron,(在前一次任务执行完成后才生效)

主要代码

实现SchedulingConfigurer接口
在接口方法configureTasks中,只有一个入参ScheduledTaskRegistrar scheduledTaskRegistrar,我们写的配置静态定时任务,作为cronTasks存储,动态定时任务作为TriggerTask存储。
抽象类

@Configuration
@EnableScheduling
public abstract class ConfigurerScheduling implements SchedulingConfigurer {

    /**
     * @brief 定时任务名称
     */
    private String schedulerName;

    /**
     * @brief 定时任务周期表达式
     */
    private String cron;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(taskScheduler());
        scheduledTaskRegistrar.addTriggerTask(
                //执行定时任务
                () -> {
                    processTask();
                },
                //设置触发器
                triggerContext -> {
                    // 动态获取cron
                    cron = getCron();
                    CronTrigger trigger = new CronTrigger(cron);
                    return trigger.nextExecutionTime(triggerContext);
                }
        );


    }

    /**
     * 设置TaskScheduler用于注册计划任务
     *
     * @return
     */
    @Bean
    public Executor taskScheduler() {
        //设置线程名称
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-%d").build();
        //创建线程池
        return Executors.newScheduledThreadPool(5, namedThreadFactory);
    }

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


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

实现类

@Configuration
@Slf4j
public class TaskDemo1 extends ConfigurerScheduling {

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

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

    @Override
    protected void processTask() {
        if (isSwitch) {
            log.info("基于接口SchedulingConfigurer的动态定时任务:"
                    + LocalDateTime.now() + ",线程名称:" + Thread.currentThread().getName()
                    + " 线程id:" + Thread.currentThread().getId());
        }
    }

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

git

https://github.com/lexiaoyao1995/schedule

posted @ 2020-11-06 17:21  刃牙  阅读(450)  评论(0编辑  收藏  举报