精华内容
下载资源
问答
  • 2021-08-14 14:45:32

    前言

      定时器是我们项目中经常会用到的,SpringBoot使用@Scheduled注解可以快速启用一个简单的定时器(详情请看我们之前的博客《SpringBoot系列——定时器》),然而这种方式的定时器缺乏灵活性,如果需要对定时器进行调整,需要重启项目才生效,本文记录SpringBoot如何灵活配置动态定时任务

    代码编写

      首先先建表,重要字段:唯一表id、Runnable任务类、Cron表达式,其他的都是一些额外补充字段

    DROP TABLE IF EXISTS `tb_task`;
    CREATE TABLE `tb_task`  (
      `task_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '定时任务id',
      `task_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务名称',
      `task_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务描述',
      `task_exp` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '定时任务Cron表达式',
      `task_status` int(1) NULL DEFAULT NULL COMMENT '定时任务状态,0停用 1启用'
    更多相关内容
  • SpringBoot实现动态定时任务,是Springboot做的动态定时任务,可以暂停,恢复,添加,删除,等操作
  • springboot动态配置定时任务(schedule),可不重启项目实现开关重启任务,改变任务定时规则
  • 主要为大家详细介绍了基于Springboot执行多个定时任务动态获取定时任务信息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • springboot 动态定时任务 springboot实现动态定时任务的方法有两种: 可以实现SchedulingConfigurer 接口(可以见springboot 动态定时任务) 整合quartz(当前文章要说的) springboot整合需要的依赖 ...

    springboot 动态定时任务

    springboot实现动态定时任务的方法有两种:

    1. 可以实现SchedulingConfigurer 接口(可以见springboot 动态定时任务
    2. 整合quartz(当前文章要说的)

    springboot整合需要的依赖

    springboot整合quartz需要导入的依赖如下

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

    在类路径下新增配置文件quartz.properties

    # scheduler名称
    org.quartz.scheduler.instanceName = MyScheduler
    # 线程池初始化数
    org.quartz.threadPool.threadCount = 10
    # 持久化规则,这里是持久化到内存,官方文档上有持久化到数据库的
    org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
    

    或者在yml文件新增配置

    spring:
      quartz:
        job-store-type: MEMORY
        schedulerName: MyScheduler
    

    quartz相关的介绍

    quartz中最重要的就是JobTrigger,可以理解为任务和触发器,任务------>触发器是一对多的关系,一个任务可以有多个触发器,触发器------>任务是一对一的关系,一个触发器只能对应一个任务

    Job的构建

    springboot中job构建的方式是继承QuartzJobBean类,QuartzJobBean类是springboot封装过的,也可以直接去实现job接口,job接口是quartz的,推荐是使用继承QuartzJobBean,代码如下

    @Slf4j
    public class ReportAutoJob extends QuartzJobBean {
    
        private String id;
    
        public void setId(String id) {
            this.id = id;
        }
    	/**
         * 调度器执行的方法
         * @param jobExecutionContext
         * @throws JobExecutionException
         */
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            log.info("自动任务开始执行");
        }
    }
    

    Trigger相关的构建

    直接使用TriggerBuilder类来构建 首先介绍触发器规则构建类 一共有四种:

    1. CalendarIntervalScheduleBuilder(相当于SimpleScheduleBuilder的升级版多支持了天周年月的间隔执行)
    2. CronScheduleBuilder(可以构建cron表达式)
    3. DailyTimeIntervalScheduleBuilder(支持复杂的构建 例如OnMondayThroughFriday方法从周一到周五,推荐自己测试一下)
    4. SimpleScheduleBuilder(简单的构建器支持配置执行次数,支持时分秒为单位的间隔执行)
     // 这里是间隔一分钟循环执行
    SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(1);
    Trigger trigger = TriggerBuilder.newTrigger()
    				// trigger名称和trigger分组名
                    .withIdentity( "triggerListener",  "triggerListenerGroup")
                    .withSchedule(simpleScheduleBuilder)
                    .build();
    

    JobDetail相关的构建

    JobDetail相关的构建

    // 创建JobDetail
    JobDataMap jobDataMap = new JobDataMap();
    jobDataMap.put("reportAutoService", this);
    jobDataMap.put("frequencyType", frequencyType);
    JobDetail myJob = JobBuilder.newJob(ReportAutoJob.class)
    		// 设置相关的参数值,在任务中可以直接获取到
            .usingJobData("id", id)
            .usingJobData(jobDataMap)
            .withIdentity(jobName + "job", jobName + "jobGroup")
            .build();
    

    JobDataMap的介绍

    JobDataMap可以给任务传参在job中可以获取到,一共有两种方式:

    1. set方法
    2. jobExecutionContext
    public class ReportAutoJob extends QuartzJobBean {
    
        private String id;
    
        /**
         * 1.Quartz自动赋值
         * @param id
         */
        public void setId(String id) {
            this.id = id;
        }
    
        /**
         * 调度器执行的方法
         * @param jobExecutionContext
         * @throws JobExecutionException
         */
        @Override
        protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            log.info("自动任务开始执行 id: {}",id);
            // 2.直接获取
            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
            ReportAutoService reportAutoService = (ReportAutoService);
        }
    }
    

    组合Trigger和Job构成一个完整的定时任务

    使用SimpleScheduleBuilder构建一个完整定时任务

    public void createListener(){
            // 规则构建器
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForever(1);
            Trigger trigger = TriggerBuilder.newTrigger()
                    // trigger名称和trigger分组名
                    .withIdentity( "triggerListener",  "triggerListenerGroup")
                    .withSchedule(simpleScheduleBuilder)
                    .build();
    		
            JobDetail myJobListener = JobBuilder.newJob(ReportTaskListening.class)
    				// JobDetail 名称和JobDetail分组名
                    .withIdentity("jobListener", "jobListenerGroup")
                    .build();
    
    
            Scheduler scheduler = null;
            try {
            	// 获取默认的Scheduler(任务调度器)
                scheduler = StdSchedulerFactory.getDefaultScheduler();
                // 组合JobDetail和Trigger构成一个完整的定时任务
                scheduler.scheduleJob(myJobListener, trigger);
                // 将所有处于待机的任务置于开始状态(这里的开始状态不是立即执行任务,而是到达任务触发器指定的触发时间才会执行)
                scheduler.start();
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    

    这里是我开发时写的创建方法可以参考

    /**
         * 创建指定的定时任务
         * @param cron cron表达式
         * @param triggerName 调度器名称
         * @param jobName 任务名称
         * @param id 任务的id这里最好自动生成
         * @param frequencyType 任务的类型(按天,按月,按周)
         * @param frequencyDay 按天传的参数,隔多少天执行一次
         * @param startTime 任务的开始时间
         */
    public void creteScheduler(String cron, String triggerName, String jobName, String id, Integer frequencyType,
                                        Integer frequencyDay, Date startTime) {
            Trigger trigger = null;
            Trigger triggerOne = null;
            // 如果是按天
            if (frequencyType.equals(ReportEnums.AutoEnums.DAY.getKey())) {
            	// 直接使用简单的构建器使用CalendarIntervalScheduleBuilder也一样的
                SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.repeatHourlyForever(24 * frequencyDay);
                
                trigger = TriggerBuilder.newTrigger()
                		// 设置任务开始时间
                        .startAt(startTime)
                        .withIdentity(triggerName + "trigger", triggerName + "triggerGroup")
                        .withSchedule(simpleScheduleBuilder)
                        .build();
            } else {
            	// 不是按天直接用cron表达式
                CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
                trigger = TriggerBuilder.newTrigger()
                        .startNow()
                        .withIdentity(triggerName + "trigger", triggerName + "triggerGroup")
                        .withSchedule(cronScheduleBuilder)
                        .build();
                if (System.currentTimeMillis() < startTime.getTime()) {
                    triggerOne = TriggerBuilder.newTrigger()
                    		// 设置任务开始时间
                            .startAt(startTime)
                            // 设置任务结束时间
                            .endAt(startTime)
                            // 可以直接在调度器上直接指定任务是那一个,参数分别是任务名称和任务分组名称 
                            .forJob(jobName + "job", jobName + "jobGroup")
                            .withIdentity(triggerName + "oneTrigger")
                            .build();
                }
            }
    		// 创建JobDetail
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("reportAutoService", this);
            jobDataMap.put("frequencyType", frequencyType);
            JobDetail myJob = JobBuilder.newJob(ReportAutoJob.class)
            		// 设置相关的参数值,在任务中可以直接获取到
                    .usingJobData("id", id)
                    .usingJobData(jobDataMap)
                    .withIdentity(jobName + "job", jobName + "jobGroup")
                    .build();
            try {
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
                // 1.注意第一次构建定时任务可以scheduleJob,但如果构架过了再使用会出现异常就是JobDetail已经注册过了
                scheduler.scheduleJob(myJob, trigger);
                // 不是按天执行
                if (!frequencyType.equals(ReportEnums.AutoEnums.DAY.getKey())&&System.currentTimeMillis() < startTime.getTime()) {
                    scheduler.scheduleJob(triggerOne);
                }
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    

    任务的恢复暂停和删除

    	/**
         *  删除指定的任务
         * @param jobName
         * @param jobGroupName
         */
        @Override
        public void deleteJob(String jobName, String jobGroupName) {
            try {
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
                scheduler.deleteJob(jobKey);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 修改 一个job的 时间表达式
         *
         * @param triggerName
         * @param triggerGroupName
         * @param jobTime
         */
        @Override
        public void updateJob(String triggerName, String triggerGroupName, String jobTime) {
            try {
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
                TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule(jobTime)).build();
                // 重启触发器
                scheduler.rescheduleJob(triggerKey, trigger);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 暂停一个job
         *
         * @param jobName
         * @param jobGroupName
         */
        @Override
        public void pauseJob(String jobName, String jobGroupName) {
            try {
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
                scheduler.pauseJob(jobKey);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 恢复一个job
         *
         * @param jobName
         * @param jobGroupName
         */
        @Override
        public void resumeJob(String jobName, String jobGroupName) {
            try {
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
                JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
                scheduler.resumeJob(jobKey);
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    
    

    获取定时任务列表,可以获取到定时任务相关的信息

    public void getTasks() {
            List<Map<String, Object>> jobList = null;
            try {
                Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
                GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
                Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
                jobList = new ArrayList<Map<String, Object>>(16);
                log.info("任务数量:{}",jobKeys.size()-1);
                for (JobKey jobKey : jobKeys) {
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        Map<String, Object> map = new HashMap<>(16);
                        map.put("jobName", jobKey.getName());
                        map.put("jobGroupName", jobKey.getGroup());
                        map.put("description", "触发器:" + trigger.getKey());
                        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                        map.put("jobStatus", triggerState.name());
                        if (trigger instanceof CronTrigger) {
                            CronTrigger cronTrigger = (CronTrigger) trigger;
                            String cronExpression = cronTrigger.getCronExpression();
                            CronExpression cron = new CronExpression(cronExpression);
                            Date now = new Date();
                            // 之前任务下次执行时间
                            String format = DateUtil.format(cron.getTimeAfter(now), "yyyy-MM-dd HH:mm:ss");
                            log.info("cron任务名称:{} 任务状态:{} 下次执行时间:{}",jobKey.getName().replace("job",""),triggerState.name(),format);
                            map.put("jobTime", cronExpression);
                        }
                        if (trigger instanceof SimpleTrigger) {
                            SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
                            if ("triggerListener".equals(simpleTrigger.getKey().getName())){
                                continue;
                            }
                            Date fireTimeAfter = simpleTrigger.getFireTimeAfter(new Date());
                            String format = DateUtil.format(fireTimeAfter, "yyyy-MM-dd HH:mm:ss");
                            log.info("simple任务名称:{} 任务状态:{} 下次执行时间:{}",jobKey.getName().replace("job",""),triggerState.name(),format);
                        }
    
                        jobList.add(map);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
    展开全文
  • (b)ThreadPoolTaskScheduler.schedule()方法会创建一个定时计划ScheduledFuture,在这个方法需要添加两个参数,Runnable(线程接口类) 和CronTrigger(定时任务触发器)(c)在ScheduledFuture中有一个cancel可以...
  • SpringBoot2 与 Quartz 整合的Demo。 后台可添加、修改、移除 定时任务。 也可查看当前任务的状态 灵活的定时任务
  • 本篇文章主要介绍了SpringBoot 创建定时任务(配合数据库动态执行),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • SpringBoot实现定时任务动态开启关闭,如有疑问联系wx: hsj179540
  • Springboot动态实现定时任务

    千次阅读 2022-02-23 14:32:19
    springboot实现动态定时任务

    spring简单集成定时任务

    直接使用@EnableScheduling开启定时任务,使用@Scheduled(cron = "")来标注任务马上就可以完成一个简单的定时任务了,这里就不贴上代码了

    spring动态实现定时任务

    创建一个SchedulingConfig配置类来初始化定时任务的线程池的大小和名称等信息

    // 开启定时任务
    @EnableScheduling 
    @Configuration
    public class SchedulingConfig {
    
        @Bean
        public TaskScheduler taskScheduler() {
            // 创建任务调度线程池
            ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
            // 初始化线程池数量
            taskScheduler.setPoolSize(4);
            // 是否将取消后的任务,从队列中删除
            taskScheduler.setRemoveOnCancelPolicy(true);
            // 设置线程名前缀
            taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
            return taskScheduler;
        }
    }
    

    查找代码可以看见sringbot中有相关的定时任务注册类,需要实现SchedulingConfigurer 类来进行注册定时任务,configureTasks在项目初始化的时候会进行执行然后通ScheduledTaskRegistrar 用来注册定时任务,这里想进行动态的增加不太现实,我们可以对这个类做一个改变使我们可以在项目启动之后获取到ScheduledTaskRegistrar这个类,代码如下:

    @Component
    public class ReportAutoTask implements SchedulingConfigurer {
    
    	private ScheduledTaskRegistrar scheduledTaskRegistrar;
    
    	/**
         * 根据taskId来储存指定的任务
         */
        private Map<String, ScheduledTask> scheduledTaskMap = new ConcurrentHashMap<>(16);
    
        /**
         * 定时任务注册(这个方法会在启动的时候进行执行)
         *
         * @param scheduledTaskRegistrar
         */
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
         	this.scheduledTaskRegistrar = scheduledTaskRegistrar;
        }
        
        public ScheduledTaskRegistrar getScheduledTaskRegistrar() {
            return scheduledTaskRegistrar;
        }
    
        public void setScheduledTaskRegistrar(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            this.scheduledTaskRegistrar = scheduledTaskRegistrar;
        }
    
        public Map<String, ScheduledTask> getScheduledTaskMap() {
            return scheduledTaskMap;
        }
    
        public void setScheduledTaskMap(Map<String, ScheduledTask> scheduledTaskMap) {
            this.scheduledTaskMap = scheduledTaskMap;
        }
    }
    

    使用ScheduledTaskRegistrar来注册定时任务

    红色的是这个类新增定时任务的方法,这里主要是用addCronTask这个方法来新增定时任务

    在这里插入图片描述

    可以看到addCronTask上图中需要一个Runnable和一个表达式的参数,这两个参数也是创建一个CronTask的要求,所以我们首先去创建一个Runnable,代码中是我自己创建的一些业务可以忽略,主要的方法就是一个run方法

    @Component
    @Slf4j
    public class ReportAutoRunnable implements Runnable {
    
        /**
         * reportAutoDTO
         */
        private ReportAutoDTO reportAutoDTO;
    
        public ReportAutoDTO getReportAutoDTO() {
            return reportAutoDTO;
        }
    
        public void setReportAutoDTO(ReportAutoDTO reportAutoDTO) {
            this.reportAutoDTO = reportAutoDTO;
        }
    
        @Autowired
        private ReportAutoService reportAutoService;
    
        @Override
        public void run() {
            String name = Thread.currentThread().getName();
            try {
                log.info("定时任务开始执行 任务id:{} ,线程名称:{}", reportAutoDTO.getId(),name);
                reportAutoService.autoReport(reportAutoDTO);
                log.info("定时任务执行完毕 任务id:{} ,线程名称:{}", reportAutoDTO.getId(),name);
            } catch (Exception ex) {
                log.info("定时任务执行出现异常 任务id:{} ,异常信息:{}", reportAutoDTO.getId(),ex.getMessage());
            }
        }
    }
    

    自定义CronTask

    创建完Runnable后可以创建一个CronTask,我是继承了一下CronTask类增加了两个属性一个id,一个名称

    public class ReportAutoCronTask extends CronTask {
        /**
         * 任务id
         */
        private String taskId;
    
        /**
         * 任务名称
         */
        private String taskName;
    
    
        public ReportAutoCronTask(Runnable runnable, String expression) {
            super(runnable, expression);
        }
    
        public ReportAutoCronTask(Runnable runnable, CronTrigger cronTrigger) {
            super(runnable, cronTrigger);
        }
    
        public ReportAutoCronTask(Runnable runnable, String expression,String taskId,String taskName){
            super(runnable, expression);
            this.taskId = taskId;
            this.taskName = taskName;
        }
    
        public String getTaskId() {
            return taskId;
        }
    
        public void setTaskId(String taskId) {
            this.taskId = taskId;
        }
    
        public String getTaskName() {
            return taskName;
        }
    
        public void setTaskName(String taskName) {
            this.taskName = taskName;
        }
    }
    

    注册并启动定时任务

    下面这一块代码就可以成功的注册一个定时任务

    // 每30秒执行一次
     String expression ="0/30 0 0 * ?";
     // 创建定时任务
    ReportAutoCronTask reportAutoCronTask = new ReportAutoCronTask(reportAutoRunnable, expression, "1111", "任务名称");
    scheduledTaskRegistrar.addCronTask(reportAutoCronTask);
     // 启动定时任务
    ScheduledTask scheduledTask = scheduledTaskRegistrar.scheduleCronTask(reportAutoCronTask);reportAutoCronTask.setFlag(true);
    scheduledTaskMap.put("1111", scheduledTask);
    

    关闭指定的定时任务

    遍历之前储存任务的集合直接调用cancel()就可以直接关闭带任务,如果需要删除的话就直接删除掉map中的定时任务就可以,想修改可以删除掉再重新新增

    for (Map.Entry<String, ScheduledTask> scheduledTaskEntry : scheduledTaskMap.entrySet()) {
                    if (scheduledTaskEntry.getKey().equals(reportAutoDTO.getId())) {
                        // 停止定时任务
                        scheduledTaskEntry.getValue().cancel();
                    }
                }
    
    展开全文
  • springboot整合Quartz实现动态配置定时任务源码
  • SpringBoot 动态添加定时任务

    千次阅读 2022-02-24 17:11:31
    springboot 手动添加/删除 定时任务

    最近的需求有一个自动发布的功能, 需要做到每次提交都要动态的添加一个定时任务

     

    代码结构

     

     1. 配置类

    package com.orion.ops.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.TaskScheduler;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
    
    /**
     * 调度器配置
     *
     * @author Jiahang Li
     * @version 1.0.0
     * @since 2022/2/14 9:51
     */
    @EnableScheduling
    @Configuration
    public class SchedulerConfig {
    
        @Bean
        public TaskScheduler taskScheduler() {
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            scheduler.setPoolSize(4);
            scheduler.setRemoveOnCancelPolicy(true);
            scheduler.setThreadNamePrefix("scheduling-task-");
            return scheduler;
        }
    
    }
    

    2. 定时任务类型枚举

    package com.orion.ops.handler.scheduler;
    
    import com.orion.ops.consts.Const;
    import com.orion.ops.handler.scheduler.impl.ReleaseTaskImpl;
    import com.orion.ops.handler.scheduler.impl.SchedulerTaskImpl;
    import lombok.AllArgsConstructor;
    
    import java.util.function.Function;
    
    /**
     * 任务类型
     *
     * @author Jiahang Li
     * @version 1.0.0
     * @since 2022/2/14 10:16
     */
    @AllArgsConstructor
    public enum TaskType {
    
        /**
         * 发布任务
         */
        RELEASE(id -> new ReleaseTaskImpl((Long) id)) {
            @Override
            public String getKey(Object params) {
                return Const.RELEASE + "-" + params;
            }
        },
    
        /**
         * 调度任务
         */
        SCHEDULER_TASK(id -> new SchedulerTaskImpl((Long) id)) {
            @Override
            public String getKey(Object params) {
                return Const.TASK + "-" + params;
            }
        },
    
        ;
    
        private final Function<Object, Runnable> factory;
    
        /**
         * 创建任务
         *
         * @param params params
         * @return task
         */
        public Runnable create(Object params) {
            return factory.apply(params);
        }
    
        /**
         * 获取 key
         *
         * @param params params
         * @return key
         */
        public abstract String getKey(Object params);
    
    }
    

    这个枚举的作用是生成定时任务的 runnable 和 定时任务的唯一值, 方便后续维护

    3. 实际执行任务实现类

    package com.orion.ops.handler.scheduler.impl;
    
    import com.orion.ops.service.api.ApplicationReleaseService;
    import com.orion.spring.SpringHolder;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * 发布任务实现
     *
     * @author Jiahang Li
     * @version 1.0.0
     * @since 2022/2/14 10:25
     */
    @Slf4j
    public class ReleaseTaskImpl implements Runnable {
    
        protected static ApplicationReleaseService applicationReleaseService = SpringHolder.getBean(ApplicationReleaseService.class);
    
        private Long releaseId;
    
        public ReleaseTaskImpl(Long releaseId) {
            this.releaseId = releaseId;
        }
    
        @Override
        public void run() {
            log.info("定时执行发布任务-触发 releaseId: {}", releaseId);
            applicationReleaseService.runnableAppRelease(releaseId, true);
        }
    
    }
    

    4. 定时任务包装器

    package com.orion.ops.handler.scheduler;
    
    import org.springframework.scheduling.TaskScheduler;
    import org.springframework.scheduling.Trigger;
    
    import java.util.Date;
    import java.util.concurrent.ScheduledFuture;
    
    /**
     * 定时 任务包装器
     *
     * @author Jiahang Li
     * @version 1.0.0
     * @since 2022/2/14 10:34
     */
    public class TimedTask {
    
        /**
         * 任务
         */
        private Runnable runnable;
    
        /**
         * 异步执行
         */
        private volatile ScheduledFuture<?> future;
    
        public TimedTask(Runnable runnable) {
            this.runnable = runnable;
        }
    
        /**
         * 提交任务 一次性
         *
         * @param scheduler scheduler
         * @param time      time
         */
        public void submit(TaskScheduler scheduler, Date time) {
            this.future = scheduler.schedule(runnable, time);
        }
    
        /**
         * 提交任务 cron表达式
         *
         * @param trigger   trigger
         * @param scheduler scheduler
         */
        public void submit(TaskScheduler scheduler, Trigger trigger) {
            this.future = scheduler.schedule(runnable, trigger);
        }
    
        /**
         * 取消定时任务
         */
        public void cancel() {
            if (future != null) {
                future.cancel(true);
            }
        }
    
    }
    

    这个类的作用是包装实际执行任务, 以及提供调度器的执行方法

    5. 任务注册器 (核心)

    package com.orion.ops.handler.scheduler;
    
    import com.orion.ops.consts.MessageConst;
    import com.orion.utils.Exceptions;
    import com.orion.utils.collect.Maps;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.scheduling.TaskScheduler;
    import org.springframework.scheduling.support.CronTrigger;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.Resource;
    import java.util.Date;
    import java.util.Map;
    
    /**
     * 任务注册器
     *
     * @author Jiahang Li
     * @version 1.0.0
     * @since 2022/2/14 10:46
     */
    @Component
    public class TaskRegister implements DisposableBean {
    
        private final Map<String, TimedTask> taskMap = Maps.newCurrentHashMap();
    
        @Resource
        @Qualifier("taskScheduler")
        private TaskScheduler scheduler;
    
        /**
         * 提交任务
         *
         * @param type   type
         * @param time   time
         * @param params params
         */
        public void submit(TaskType type, Date time, Object params) {
            // 获取任务
            TimedTask timedTask = this.getTask(type, params);
            // 执行任务
            timedTask.submit(scheduler, time);
        }
    
        /**
         * 提交任务
         *
         * @param type   type
         * @param cron   cron
         * @param params params
         */
        public void submit(TaskType type, String cron, Object params) {
            // 获取任务
            TimedTask timedTask = this.getTask(type, params);
            // 执行任务
            timedTask.submit(scheduler, new CronTrigger(cron));
        }
    
        /**
         * 获取任务
         *
         * @param type   type
         * @param params params
         */
        private TimedTask getTask(TaskType type, Object params) {
            // 生成任务
            Runnable runnable = type.create(params);
            String key = type.getKey(params);
            // 判断是否存在任务
            if (taskMap.containsKey(key)) {
                throw Exceptions.init(MessageConst.TASK_PRESENT);
            }
            TimedTask timedTask = new TimedTask(runnable);
            taskMap.put(key, timedTask);
            return timedTask;
        }
    
        /**
         * 取消任务
         *
         * @param type   type
         * @param params params
         */
        public void cancel(TaskType type, Object params) {
            String key = type.getKey(params);
            TimedTask task = taskMap.get(key);
            if (task != null) {
                taskMap.remove(key);
                task.cancel();
            }
        }
    
        /**
         * 是否存在
         *
         * @param type   type
         * @param params params
         */
        public boolean has(TaskType type, Object params) {
            return taskMap.containsKey(type.getKey(params));
        }
    
        @Override
        public void destroy() {
            taskMap.values().forEach(TimedTask::cancel);
            taskMap.clear();
        }
    
    }
    

    这个类提供了执行, 提交任务的api, 实现 DisposableBean 接口, 便于在bean销毁时将任务一起销毁

    6. 使用

    
        @Resource
        private TaskRegister taskRegister;
        
        /**
         * 提交发布
         */
        @RequestMapping("/submit")
        @EventLog(EventType.SUBMIT_RELEASE)
        public Long submitAppRelease(@RequestBody ApplicationReleaseRequest request) {
            Valid.notBlank(request.getTitle());
            Valid.notNull(request.getAppId());
            Valid.notNull(request.getProfileId());
            Valid.notNull(request.getBuildId());
            Valid.notEmpty(request.getMachineIdList());
            TimedReleaseType timedReleaseType = Valid.notNull(TimedReleaseType.of(request.getTimedRelease()));
            if (TimedReleaseType.TIMED.equals(timedReleaseType)) {
                Date timedReleaseTime = Valid.notNull(request.getTimedReleaseTime());
                Valid.isTrue(timedReleaseTime.compareTo(new Date()) > 0, MessageConst.TIMED_GREATER_THAN_NOW);
            }
            // 提交
            Long id = applicationReleaseService.submitAppRelease(request);
            // 提交任务
            if (TimedReleaseType.TIMED.equals(timedReleaseType)) {
                taskRegister.submit(TaskType.RELEASE, request.getTimedReleaseTime(), id);
            }
            return id;
        }
    

    最后

           这是一个简单的动态添加定时任务的工具, 有很多的改造空间, 比如想持久化可以插入到库中, 定义一个 CommandLineRunner 在启动时将定时任务全部加载, 还可以给任务加钩子自动提交,自动删除等, 代码直接cv一定会报错, 就是一些工具, 常量类会报错, 改改就好了, 本人已亲测可用, 有什么问题可以在评论区沟通

    展开全文
  • SpringBoot设置动态定时任务

    千次阅读 2022-03-22 10:40:17
    之前写过文章记录怎么在SpringBoot项目中简单使用定时任务,不过由于要借助cron表达式且都提前定义好放在配置文件里,不能在项目运行中动态修改任务执行时间,实在不太灵活。 经过网上搜索学习后,特此记录如何在...
  • 主要介绍了SpringBoot并发定时任务动态定时任务实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 地址:GitHub - guoyixing/super-scheduled: SpringBoot的定时调用的加强工具,实现定时任务动态管理,后续加入可视化管理、调度日志、集群任务统一管理
  • springboot实现动态定时任务

    千次阅读 2021-02-03 15:27:34
    //设置定时任务工厂模式 //项目启动时默认给spring容器添加动态定时任务 this.addJob("job" + 100L, 100L, JobTask.class, "0/2 * * * * ?"); } catch (SchedulerException e) { logger.error(e.getMessage(), e)...
  • 基于springBoot动态配置定时任务

    千次阅读 2022-01-26 17:11:56
    /** * @ClassName ScheduledTaskService * @Description 定时任务接口 * @Author * @Date * @Version 1.0 */ public interface ScheduledTaskService { /** * 根据任务key 启动任务 */ Boolean start(String task...
  • 我们知道SpringBoot能使用@Scheduled注解来进行定时任务的控制,该注解需要配合Cron表达式以及在启动类上添加@EnableScheduling注解才能使用。 不过我们现在的假定情景并不是程序员设定的定时任务,而是用户可以在...
  • SpringBoot-动态定时任务调度 一、业务场景 先说业务场景,根据用户输入的cron表达式进行定时调度,举个例子:如图 根据用户输入的参数,生成表达式,然后定时去执行相应的业务逻辑。 二、Controller层(不是重点...
  • 主要介绍了springboot schedule 解决定时任务不执行的问题,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 主要为大家详细介绍了SpringBoot下RabbitMq实现定时任务,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要为大家详细介绍了SpringBoot实现定时任务和异步调用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要介绍了SpringBoot执行定时任务@Scheduled的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
  • SpringBoot动态配置定时任务

    千次阅读 2020-10-15 16:52:45
    Springboot中创建定时任务,实现动态配置定时任务 启动类开启定时任务 @EnableScheduling //开启定时任务 @EnableEurekaClient @SpringBootApplication @EnableElasticsearchRepositories(basePackages = ...
  • https://www.cnblogs.com/zt007/p/8954096.html
  • 在实际设计开发“测试集”功能的时候,为每一个测试集提供了一个定时任务cron表达式字段,代码需要实现将具备cron表达式的测试集动态加入到定时任务中,按cron表达式的规则定时执行测试集中的接口用例 二、...
  • Springboot整合Quartz实现定时任务数据库动态配置,新增任务、修改cron表达式、暂停任务、恢复任务、删除任务等操作
  • `created_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `cron` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '定时任务表达式', `task_name`...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,646
精华内容 13,058
关键字:

springboot动态定时任务

spring 订阅