SpringBoot 使用 Quartz 管理定时任务

一、Quartz 简介

Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵 活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,EJB作业预构 建,JavaMail及其它,支持cron-like表达式等等。

二、引入 maven 依赖

<!-- Quartz 定时任务 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

三、编写代码

1、编写 Service 接口类

package com.cxy.job;

import java.util.Date;

import org.quartz.Job;
import org.quartz.JobDataMap;

public interface SysQuartzService {
	
	/**
	 * 添加定时任务
	 * @param name 任务名称
	 * @param iClass JOB类
	 * @param cron 表达式
	 * @param param 参数
	 */
	public void schedulerAdd(String name, Class<? extends Job> iClass, String cron, JobDataMap param);
	
	/**
	 * 添加定时任务
	 * @param name 任务名称
	 * @param iClass JOB类
	 * @param cron 表达式
	 * @param startTime 开始时间 (选填)
	 * @param endTime 结束时间 (选填)
	 * @param param 参数
	 */
	public void schedulerAdd(String name, Class<? extends Job> iClass, String cron, Date startTime, Date endTime, JobDataMap param);
	
	/**
	 * 添加定时任务
	 * @param name 任务名称
	 * @param iClass JOB类
	 * @param count 运行的次数 (-1 无限执行、n 执行次数,索引0开始)
	 * @param second 每次间隔的时间 (s)
	 * @param param 参数
	 */
	public void schedulerAdd(String name, Class<? extends Job> iClass, int count, int second, JobDataMap param);
	
	/**
	 * 添加定时任务
	 * @param name 任务名称
	 * @param iClass JOB类
	 * @param count 运行的次数 (-1 无限执行、n 执行次数,索引0开始)
	 * @param second 每次间隔的时间 (s)
	 * @param startTime 开始时间 (选填)
	 * @param endTime 结束时间 (选填)
	 * @param param 参数
	 */
	public void schedulerAdd(String name, Class<? extends Job> iClass, int count, int second, Date startTime, Date endTime, JobDataMap param);
	
	/**
	 * 删除定时任务
	 * @param name 任务名称
	 */
	public void schedulerDelete(String name);
	
}

2、编写 ServiceImpl 实现类

package com.cxy.job;

import lombok.extern.slf4j.Slf4j;

import java.util.Date;

import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class SysQuartzServiceImpl implements SysQuartzService {

    @Autowired
    private Scheduler scheduler;
    
    @Override
    public void schedulerAdd(String name, Class<? extends Job> iClass, String cron, JobDataMap param) {
    	schedulerAdd(name, iClass, cron, null, null, param);
    }
    
    @Override
	public void schedulerAdd(String name, Class<? extends Job> iClass, String cron, Date startTime, Date endTime, JobDataMap param) {
    	try {
            // 删除旧任务
            schedulerDelete(name);
            // 启动调度器
            scheduler.start();
            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(iClass).withIdentity(name).setJobData(param).build();
            // 表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            // 按新的 cronExpression 表达式构建一个新的trigger
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            triggerBuilder.withIdentity(name);
            // 设置开始时间
            if(startTime!=null) triggerBuilder.startAt(startTime);
            // 设置结束时间
            if(endTime!=null) triggerBuilder.endAt(endTime);
            triggerBuilder.withSchedule(scheduleBuilder);
            scheduler.scheduleJob(jobDetail, triggerBuilder.build());
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        } catch (RuntimeException e) {
            log.error(e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
	}
    
    @Override
	public void schedulerAdd(String name, Class<? extends Job> iClass, int count, int second, JobDataMap param) {
    	schedulerAdd(name, iClass, count, second, null, null, param);
	}
    
    @Override
	public void schedulerAdd(String name, Class<? extends Job> iClass, int count, int second, Date startTime, Date endTime, JobDataMap param) {
    	try {
            // 删除旧任务
            schedulerDelete(name);
            // 启动调度器
            scheduler.start();
            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(iClass).withIdentity(name).setJobData(param).build();
            // 表达式调度构建器(即任务执行的时间)
            SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(second).withRepeatCount(count);
            // 按新的cronExpression表达式构建一个新的trigger
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            triggerBuilder.withIdentity(name);
            triggerBuilder.withSchedule(scheduleBuilder);	     
            // 设置开始时间
            if(startTime!=null) triggerBuilder.startAt(startTime);
            // 设置结束时间
            if(endTime!=null) triggerBuilder.endAt(endTime);
            scheduler.scheduleJob(jobDetail, triggerBuilder.build());
    	} catch (SchedulerException e) {
            log.error(e.getMessage());
        } catch (RuntimeException e) {
            log.error(e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
	}
    
    /**
     * 删除定时任务
     *
     * @param className
     */
    @Override
    public void schedulerDelete(String className) {
        try {
            scheduler.pauseTrigger(TriggerKey.triggerKey(className));
            scheduler.unscheduleJob(TriggerKey.triggerKey(className));
            scheduler.deleteJob(JobKey.jobKey(className));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

}

3、编写 Job 执行类

package com.cxy.job.task;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JobTest implements Job {
	
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		String jobName = context.getJobDetail().getKey().toString().substring(8);
		JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
		String param = jobDataMap.getString("param");
		log.info("执行 JobTest : {} - {}", jobName, param);
	}

}

4、编写 Init 初始化类

package com.erayton.taxi.timer;

import java.text.SimpleDateFormat;

import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.erayton.taxi.job.SysQuartzService;
import com.erayton.taxi.timer.job.JobTest;

@Component
@Order(0)
@Async
public class JobInit  implements ApplicationRunner{
	
	@Autowired
    private SysQuartzService sysQuartzService;
	
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	@Override
	public void run(ApplicationArguments args) throws Exception {
		
		JobDataMap jobDataMap = new JobDataMap();
		jobDataMap.put("param", "我的参数");
		
		/**
		 * 1、秒针 0、10、20、30、40、50 秒时触发执行
		 * 2、任务不停止
		 */
		sysQuartzService.schedulerAdd("Test10s-1", JobTest.class, "0/10 * * * * ?", jobDataMap);
		
		/**
		 * 1、秒针 0、10、20、30、40、50 秒时触发执行
		 * 2、任务结束于 2022-03-28 17:50:00
		 */
		sysQuartzService.schedulerAdd("Test10s-2", JobTest.class, "0/10 * * * * ?", null, sdf.parse("2022-03-28 17:50:00"), jobDataMap);
		
		/**
		 * 1、秒针 0、10、20、30、40、50 秒时触发执行
		 * 2、任务开始于 2022-03-28 17:10:00
		 * 3、任务结束于 2022-03-28 17:50:00
		 */
		sysQuartzService.schedulerAdd("Test10s-3", JobTest.class, "0/10 * * * * ?", sdf.parse("2022-03-28 17:10:00"), sdf.parse("2022-03-28 17:50:00"), jobDataMap);
		
		/**
		 * 1、每 10 秒钟触发执行
		 * 2、任务不停止
		 */
		sysQuartzService.schedulerAdd("Test10s-4", JobTest.class, -1, 10, jobDataMap);
		
		/**
		 * 1、每 10 秒钟触发执行
		 * 2、任务结束于 2022-03-28 17:50:00
		 */
		sysQuartzService.schedulerAdd("Test10s-5", JobTest.class, -1, 10, null, sdf.parse("2022-03-28 17:50:00"), jobDataMap);
		
		/**
		 * 1、每 10 秒钟触发执行
		 * 2、任务开始于 2022-03-28 17:10:00
		 * 3、任务结束于 2022-03-28 17:50:00
		 */
		sysQuartzService.schedulerAdd("Test10s-6", JobTest.class, -1, 10, sdf.parse("2022-03-28 17:10:00"), sdf.parse("2022-03-28 17:50:00"), jobDataMap);
		
		/**
		 * 1、每 10 秒钟触发执行
		 * 2、执行 5 次后任务结束 (索引从 0 开始计算)
		 */
		sysQuartzService.schedulerAdd("Test10s-7", JobTest.class, 4, 10, jobDataMap);
		
	}
	
}

四、总结

1、可根据自己的业务情况定制数据库存储【定时任务】

2、通过类名获取 Class

// 例如 className = com.cxy.job.task.JobTest
private static Job getClass(String className) throws Exception {
    Class<?> class1 = Class.forName(className);
    return (Job) class1.newInstance();
}

3、类名正则表达式

/^[a-zA-Z]+(\.([a-zA-Z])+)+$/

4、cron 可以使用 Quartz 自带验证方法

org.quartz.CronExpression.isValidExpression(cron);
  • 打赏
请选择打赏方式
  • 微信
  • 支付宝

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部