美文网首页
扩展Spring Boot Web应用 - 增加动态定时任务

扩展Spring Boot Web应用 - 增加动态定时任务

作者: nzdxwl | 来源:发表于2019-12-06 09:37 被阅读0次

    前面添加过简单的定时任务,但这个任务启动后就会一直运行直到应用结束,如果打算不重启应用就调整任务的定时执行时间,或者暂停任务甚至动态添加新的任务呢?还是有办法做到的,下面就开始我们的扩展。

    添加依赖

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

    代码修改

    1. 启动类添加@EnableScheduling注解
    2. 配置文件添加以下配置,第一行指定使用jdbc连接数据库,第二行配置启动时自动初始化quartz相关表,第三行配置quart数据库表文件路径,由于只需要初始化一次,所以当生成相应表后后面两行注释掉。
    spring.quartz.job-store-type=jdbc
    #spring.quartz.jdbc.initialize-schema=always
    #spring.quartz.jdbc.schema=classpath:quartz-mysql.sql
    

    quart数据库表文件可以在quartz scheduler官网下载发布包,这里使用的是2.2.3的版本,下载解压后进入quartz-2.2.3\docs\dbTables,复制tables_mysql_innodb.sql到项目src\main\resource目录下并修改文件名称和配置一致。

    1. 数据源配置,除了在配置文件配置连接数据库的相关配置外,代码中也添加以下内容:
        @Bean
        @Primary
        public DataSourceProperties defaultDsProperties() {
            return new DataSourceProperties();
        }
    
        @Bean
        @QuartzDataSource  //指示Quartz使用此数据源进行数据库操作
        public DataSource getDataSource() {
            return defaultDsProperties().initializeDataSourceBuilder().build();
        }
    
    1. 自定义任务类:
    public class CustJob implements Job{
        
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            //这里是固定的业务逻辑,方便演示只简单打印信息
            System.out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) + " -- Hello, world!!");
        }
    }
    
    1. 添加任务控制器类:
    @RestController
    @RequestMapping("/job")
    public class QuartzJobController {
    
        @Autowired
        private SchedulerFactoryBean schedulerFactory;
    
        /**
         * 添加定时任务
         * @param jobClassName: 自定义的任务类名称,例如:CustJob,不需要包和.class后缀
         * @param jobGroupName:自定义的任务组,可随意设置
         * @param cronExpression: 定时表达式
         * @throws Exception
         */
        @PostMapping(value = "/add")
        public void addjob(@RequestParam(value = "jobClassName") String jobClassName,
                @RequestParam(value = "jobGroupName") String jobGroupName,
                @RequestParam(value = "cronExpression") String cronExpression) throws Exception {
    
            // 启动调度器
            Scheduler scheduler = schedulerFactory.getScheduler();
            scheduler.start();
            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(CustJob.class).withIdentity(jobClassName, jobGroupName).build();
            // 表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
                    .withSchedule(scheduleBuilder).build();
            try {
                scheduler.scheduleJob(jobDetail, trigger);
    
            } catch (SchedulerException e) {
                System.out.println("创建定时任务失败" + e);
                throw new Exception("创建定时任务失败");
            }       
        }
    
        @PostMapping(value = "/reschedule")
        public void reschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
            try {
    
                Scheduler scheduler = schedulerFactory.getScheduler();
                TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
                // 表达式调度构建器         
                CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                // 按新的cronExpression表达式重新构建trigger
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
                                                      .withMisfireHandlingInstructionFireAndProceed();
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
            } catch (SchedulerException e) {
                System.out.println("更新定时任务失败" + e);
                throw new Exception("更新定时任务失败");
            }
        }
        
        
        @PostMapping(value = "/pause")
        public void pausejob(@RequestParam(value = "jobClassName") String jobClassName,
                @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
            
            schedulerFactory.getScheduler().pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
        }
    
        @PostMapping(value = "/resume")
        public void resumejob(@RequestParam(value = "jobClassName") String jobClassName,
                @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
            
            schedulerFactory.getScheduler().resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
        }   
        
    
        @PostMapping(value = "/delete")
        public void deletejob(@RequestParam(value = "jobClassName") String jobClassName,
                @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
            
            schedulerFactory.getScheduler().pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
            schedulerFactory.getScheduler().unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
            schedulerFactory.getScheduler().deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
        }
        
    }
    

    最后编译和启动应用,可以使用postman测试相应的接口,如果有配置swagger的话,也可以在接口文档页面中测试。
    有多种动态任务的话,可以定义不同的任务类,或者修改自定义任务类并扩展Controller类接口增添一些控制参数,使得任务类支持不同的业务逻辑。

    相关文章

      网友评论

          本文标题:扩展Spring Boot Web应用 - 增加动态定时任务

          本文链接:https://www.haomeiwen.com/subject/dybfgctx.html