【总结】spring定时任务

1.spring - @schedule定时任务器

1.1.实现

1.引入依赖
spring3.0后自带的定时任务器,所以只需引入spring依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

2.定时任务类

@Component
public class ScheduleDemo {
    @Scheduled(cron = "0/2 * * * * ?")
    public void scheduleMethod(){
        System.out.println("定时器被触发" + new Date());
    }
}

3.启动类加@EnableScheduling注解

4.效果.每两秒打印一次

1.2.cron表达式

1.cron表达式是一个字符串,分为6或7个域,每一个域代标一个含义

2.cron有如下两种语法格式:
(1)秒 分 时 日 月 星期 年
(2)秒 分 时 日 月 星期
推荐使用6个域的表达式(有的定时任务器要求为6个域,否则会出错)
(注意:星期的1表示星期日)

3.各字段的含义

(1):表示匹配该域的任意值。假如在Minutes域使用, 即表示每分钟都会触发事件。
(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样
(3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(5)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三
(6)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次

2.spring - SchedulingConfigurer定时任务器

2.1 SchedulingConfigurer介绍

@Schedule注解的一个缺点就是其定时时间不能动态更改,它适用于具有固定任务周期的任务,若要修改任务执行周期,只能走“停服务→修改任务执行周期→重启服务”这条路。
而基于 SchedulingConfigurer 接口方式可以做到。SchedulingConfigurer 接口可以实现在@Configuration 类上,同时不要忘了,还需要@EnableScheduling 注解的支持

2.2 SchedulingConfigurer实现

1.创建数据库表

CREATE TABLE `trip_job_lock`  (
  `job_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '定时任务名称',
  `is_lock` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否开启任务 1-开启,0-关闭',
  `job_cron` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务执行时间间隔',
  `job_desc` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务中午描述',
  PRIMARY KEY (`job_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '定时任务配置表' ROW_FORMAT = Dynamic;

INSERT INTO `trip_job_lock` VALUES ('1', NULL, '0/5 * * * * ?', NULL);

2.SchedulingConfigurer接口
实现SchedulingConfigurer接口重写configureTasks方法

@Component
public class SchedulerTask implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        this.registrar = scheduledTaskRegistrar;
        taskTriggerModels = new ArrayList<>();
        logger.info("初始化定时任务配置");
        //"update OrderTask set IsRunning = 0 where IsExecute = 1 and Isdel = 0"
        orderTaskMapper.init();
        scheduledTaskRegistrar.addTriggerTask(SyncCompeteAgentInfoByCaChange(), getTrigger(TaskEnum.SyncCompeteAgentInfoByCaChange.getTaskCode()));
        //用于controller里,重新启动或更新任务
        List<TriggerTask> tasks = scheduledTaskRegistrar.getTriggerTaskList();
        if (tasks != null && tasks.size() > 0) {
            for (TriggerTask task : tasks) {
                Optional<TaskTriggerModel> optional = taskTriggerModels.stream().filter(o -> o.getTrigger() == task.getTrigger()).findFirst();
                if (optional.isPresent()) {
                    optional.get().setRunnable(task.getRunnable());
                }
            }
        }

    /**
     * 从数据库中获取触发时间
     */
    private Trigger getTrigger(String taskCode) {
        Trigger trigger = new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                OrderTask task = orderTaskMapper.selectByTaskCode(taskCode);
                int isContinue = 1;
                String[] codeArry = {"2", "3", "6"};
                if ("uat".equals(proAction) && !Arrays.asList(codeArry).contains(taskCode)) {
                    isContinue = 0;
                }
                if (task != null && isContinue == 1) {
                    logger.info("任务编码:" + taskCode + " cron: " + task.getCron());
                    // 触发器
                    CronTrigger trigger = new CronTrigger(task.getCron());
                    return trigger.nextExecutionTime(triggerContext);
                } else {
                    logger.info("定时任务初始化失败,任务编码:{},请检查数据库中的任务状态。", taskCode);
                    return null;
                }
            }
        };
        TaskTriggerModel model = new TaskTriggerModel();
        model.setTaskCode(taskCode);
        model.setTrigger(trigger);
        taskTriggerModels.add(model);
        return trigger;
    }
}

3.schedule定时任务原理

JUC 包中的 Executor 架构带来了线程的创建与执行的分离。Executor 的继承者 ExecutorService 下面衍生出了两个重要的实现类,他们分别是
ThreadPoolExecutor 线程池
ScheduledThreadPoolExecutor 支持周期性任务的线程池
通过 ThreadPoolExecutor 可以实现各式各样的自定义线程池,而 ScheduledThreadPoolExecutor 类则在自定义线程池的基础上增加了周期性执行任务的功能

posted @ 2020-11-17 09:14  mu_阿成  阅读(3462)  评论(0)    收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css