您的位置:

使用SpringBoot实现动态定时任务

一、引言

动态定时任务是指可以动态添加、修改、删除定时任务的功能,一般应用于需要灵活控制定时任务的业务场景。SpringBoot作为一个非常火热的Java框架,提供了非常便捷的定时任务的实现方式,本文主要介绍如何使用SpringBoot实现动态定时任务。下面我们将从多个方面进行详细的阐述。

二、定时任务的基本实现方式

SpringBoot中基于注解的定时任务实现方式非常便捷,只需在任务方法上添加注解@Scheduled即可实现简单的定时任务功能。例如,在SpringBoot应用程序中,执行某个方法,每隔一段时间输出某个信息,可以使用如下注解配置:

    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() {
        logger.info("当前时间是:{}", dateFormat.format(new Date()));
    }

上述代码中,@Scheduled注解指示该方法应该执行一个定时任务,fixedRate是一个参数,它规定任务每隔多少毫秒执行一次。在这种情况下,任务将每隔5秒查询一次数据库并记录当前时间。但是,这种方法只适合固定间隔的任务,如果想要控制任务的实现,就需要使用Cron表达式来定义定时策略。例如:

    @Scheduled(cron = "0 15 10 ? * *")
    public void scheduledTask() {
        // 执行任务
    }

上述代码中,@Scheduled注解中通过cron属性设置了一个Cron表达式,它表示任务将在每天的上午10点15分执行。

三、动态定时任务的实现方式

1. 存储定时任务信息

为了实现动态定时任务的功能,我们需要在数据库中存储定时任务的相关信息,如任务名称、任务描述、Cron表达式等。 我们可以建立一个定时任务数据表,将任务的相关信息存储在该表中。

CREATE TABLE `task_schedule` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务ID',
  `job_name` varchar(64) NOT NULL COMMENT '任务名称',
  `job_desc` varchar(256) DEFAULT NULL COMMENT '任务描述',
  `job_group` varchar(64) DEFAULT NULL COMMENT '任务所属分组',
  `job_cron` varchar(64) NOT NULL COMMENT 'Cron表达式',
  `job_status` int(2) NOT NULL COMMENT '任务状态,1:启用,0:禁用',
  `job_start_time` datetime DEFAULT NULL COMMENT '任务开始时间',
  `job_end_time` datetime DEFAULT NULL COMMENT '任务结束时间',
  `create_time` datetime NOT NULL COMMENT '任务创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '任务更新时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='动态任务调度表';

2. 使用Quartz实现动态定时任务

SpringBoot集成了Quartz,并且提供了官方的Quartz工具包starter,因此,我们可以基于Quartz实现动态定时任务。

2.1 添加依赖

首先我们需要添加Quartz相关的依赖和SpringBoot的依赖。

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

2.2 实现动态添加任务

SpringBoot提供了一个SchedulerFactoryBean来配置Quartz,我们可以通过SchedulerFactoryBean创建调度工厂,并使用任务调度工厂创建Scheduler调度器。下面我们来实现动态添加任务的代码。

/**
 * 任务调度核心类
 */
@Configuration
public class QuartzConfig {

    @Autowired
    private DataSource dataSource;

    /**
     * 配置SchedulerFactoryBean
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        // 加载quartz数据源
        schedulerFactoryBean.setDataSource(dataSource);
        return schedulerFactoryBean;
    }

    /**
     * 创建Scheduler定时器
     */
    @Bean
    public Scheduler scheduler() throws SchedulerException {
        return schedulerFactoryBean().getScheduler();
    }

    /**
     * 添加任务
     * @param jobName 任务名称
     * @param jobGroup 任务分组
     * @param cronExpression Cron表达式
     * @param jobClass 任务类
     * @throws SchedulerException
     */
    public void addJob(String jobName, String jobGroup, String cronExpression, Class jobClass) throws SchedulerException {

        // 获取调度器
        Scheduler scheduler = scheduler();

        // 构建任务信息
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobName, jobGroup)
                .build();

        // 设置任务触发器
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, jobGroup)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .build();

        // 调度器中添加任务
        scheduler.scheduleJob(jobDetail, cronTrigger);

        // 启动调度器
        if(!scheduler.isShutdown()) {
            scheduler.start();
        }
    }

}

上述代码中,我们定义了一个SchedulerFactoryBean的Bean,并通过@Autowired注解将数据源注入到该Bean中。然后通过该Bean的方法getScheduler()获取到Scheduler调度器。 可以看到,我们通过Quartz提供的JobBuilder和TriggerBuilder创建JobDetail和CronTrigger决定了动态定时任务的任务执行和触发方式。最后调用调度器的方法scheduleJob()将任务添加到调度器中。

2.3 动态添加任务的调用

我们可以在任意位置调用添加任务方法addJob(),从而实现动态添加任务的功能。

    @Autowired
    private QuartzConfig quartzConfig;

    public boolean addTask(String jobName, String jobGroup, String cron, Class jobClass) {
        try {
            quartzConfig.addJob(jobName, jobGroup, cron, jobClass);
            return true;
        } catch (SchedulerException e) {
            // ...
            return false;
        }
    }

2.4 动态修改任务

动态修改任务需要调用Quartz的Scheduler修改任务,我们可以在上一步的代码中添加该功能。

    /**
     * 修改任务
     * @param jobName 任务名称
     * @param jobGroup 任务分组
     * @param cronExpression Cron表达式
     * @throws SchedulerException
     */
    public void modifyJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException {

        // 获取调度器
        Scheduler scheduler = scheduler();

        // 根据任务名称和分组名称获取任务Key
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);

        // 根据任务Key获取Trigger
        CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);

        // 重新设置Cron表达式
        CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule(cronExpression);
        CronTrigger newTrigger = cronTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(builder).build();

        // 重置触发器中的Cron表达式
        scheduler.rescheduleJob(triggerKey, newTrigger);

    }

2.5 动态删除任务

在Quartz中删除任务需要调用Scheduler删除任务,Quartz提供了暂停、恢复和删除任务的方法,我们可以基于这些方法实现动态删除任务的功能。

    /**
     * 删除任务
     * @param jobName 任务名称
     * @param jobGroup 任务分组
     * @throws SchedulerException
     */
    public void deleteJob(String jobName, String jobGroup) throws SchedulerException {

        // 获取调度器
        Scheduler scheduler = scheduler();

        // 根据任务名称和分组名称获取任务Key
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);

        // 删除任务
        scheduler.deleteJob(jobKey);

    }

四、总结

本文详细介绍了如何使用SpringBoot实现动态定时任务功能,从定时任务的基本实现方式到动态定时任务的实现方式,逐步展示了动态定时任务的全过程,相信读完本文后,你已经掌握了使用SpringBoot实现动态定时任务的方法。