简介

Springboot 2 整合 quartz 定时任务
(非原创,全文都是参考的简书作者的代码)
记录一下折腾的过程,防止以后忘记
参考:https://www.jianshu.com/p/b9955ee663b5



基本代码


pom.xml

  1. <!-- quartz -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-quartz</artifactId>
  5. </dependency>

数据库 sys_schedule_job

  1. CREATE TABLE `sys_schedule_job` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '任务id',
  3. `job_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '任务名称',
  4. `cron_expression` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT 'cron表达式',
  5. `bean_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '服务名称',
  6. `method_name` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '方法名称',
  7. `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态 0 启动 1 停止',
  8. `user_id` int(11) NOT NULL COMMENT '创建人id 关联sys_user',
  9. `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  10. `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  11. `del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '软删除标记 0 正常 1 删除',
  12. PRIMARY KEY (`id`) USING BTREE
  13. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='定时任务';

sys_schedule_job 表对应的类

包括:
SysScheduleJob.java,
ISysScheduleJobService.java,
SysScheduleJobServiceImpl.java,
SysScheduleJobMapper.java,
SysScheduleJobMapper.xml

(由mybatis plus生成,这里就全部略过了… )


配置 QuartzConfig.java

  1. @Configuration
  2. public class QuartzConfig {
  3. @Bean
  4. public SchedulerFactoryBean schedulerFactoryBean(){
  5. SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
  6. //覆盖已存在的任务
  7. schedulerFactoryBean.setOverwriteExistingJobs(true);
  8. //延时60秒启动定时任务,避免系统未完全启动却开始执行定时任务的情况
  9. schedulerFactoryBean.setStartupDelay(60);
  10. return schedulerFactoryBean;
  11. }
  12. /** 创建schedule **/
  13. @Bean(name = "scheduler")
  14. public Scheduler scheduler() {
  15. return schedulerFactoryBean().getScheduler();
  16. }
  17. }

枚举类:JobOperateEnum.java

  1. public enum JobOperateEnum {
  2. START(0, "启动"),
  3. PAUSE(1, "暂停"),
  4. DELETE(2, "删除");
  5. private final Integer value;
  6. private final String desc;
  7. JobOperateEnum(final Integer value, final String desc) {
  8. this.value = value;
  9. this.desc = desc;
  10. }
  11. public Serializable getValue() {
  12. return this.value;
  13. }
  14. public String getDesc() {
  15. return this.desc;
  16. }
  17. public String getEnumName() {
  18. return name();
  19. }
  20. }

工厂类:QuartzFactory.java

  1. public class QuartzFactory implements Job {
  2. @Override
  3. public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
  4. //获取调度数据
  5. SysScheduleJob scheduleJob = (SysScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob");
  6. //获取对应的Bean
  7. Object object = SpringUtil.getBean(scheduleJob.getBeanName());
  8. try {
  9. //利用反射执行对应方法
  10. Method method = object.getClass().getMethod(scheduleJob.getMethodName());
  11. method.invoke(object);
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. }

服务层 IQuartzService.java

  1. public interface IQuartzService {
  2. /**
  3. * 服务器启动执行定时任务
  4. */
  5. void timingTask();
  6. /**
  7. * 新增定时任务
  8. * @param job 任务
  9. */
  10. void addJob(SysScheduleJob job);
  11. /**
  12. * 操作定时任务
  13. * @param jobOperateEnum 操作枚举
  14. * @param job 任务
  15. */
  16. void operateJob(JobOperateEnum jobOperateEnum, SysScheduleJob job) throws SchedulerException;
  17. /**
  18. * 启动所有任务
  19. */
  20. void startAllJob() throws SchedulerException;
  21. /**
  22. * 暂停所有任务
  23. */
  24. void pauseAllJob() throws SchedulerException;
  25. }

服务层实现类 QuartzServiceImpl.java

  1. @Service
  2. public class QuartzServiceImpl implements IQuartzService {
  3. /**
  4. * 调度器
  5. */
  6. @Autowired
  7. private Scheduler scheduler;
  8. @Autowired
  9. private ISysScheduleJobService jobService;
  10. @Override
  11. public void timingTask() {
  12. //查询数据库是否存在需要定时的任务
  13. List<SysScheduleJob> scheduleJobs = jobService.list();
  14. if (scheduleJobs != null) {
  15. scheduleJobs.forEach(this::addJob);
  16. }
  17. }
  18. @Override
  19. public void addJob(SysScheduleJob job) {
  20. try {
  21. //创建触发器
  22. Trigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName())
  23. .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression()))
  24. .startNow()
  25. .build();
  26. //创建任务
  27. JobDetail jobDetail = JobBuilder.newJob(QuartzFactory.class)
  28. .withIdentity(job.getJobName())
  29. .build();
  30. //传入调度的数据,在QuartzFactory中需要使用
  31. jobDetail.getJobDataMap().put("scheduleJob", job);
  32. //调度作业
  33. scheduler.scheduleJob(jobDetail, trigger);
  34. } catch (Exception e) {
  35. throw new RuntimeException(e);
  36. }
  37. }
  38. @Override
  39. public void operateJob(JobOperateEnum jobOperateEnum, SysScheduleJob job) throws SchedulerException {
  40. JobKey jobKey = new JobKey(job.getJobName());
  41. JobDetail jobDetail = scheduler.getJobDetail(jobKey);
  42. if (jobDetail == null) {
  43. //抛异常
  44. }
  45. switch (jobOperateEnum) {
  46. case START:
  47. scheduler.resumeJob(jobKey);
  48. break;
  49. case PAUSE:
  50. scheduler.pauseJob(jobKey);
  51. break;
  52. case DELETE:
  53. scheduler.deleteJob(jobKey);
  54. break;
  55. }
  56. }
  57. @Override
  58. public void startAllJob() throws SchedulerException {
  59. scheduler.start();
  60. }
  61. @Override
  62. public void pauseAllJob() throws SchedulerException {
  63. scheduler.standby();
  64. }
  65. }

JobSchedule.java 实现开机自运行

  1. /**
  2. * 实现项目启动后自运行
  3. */
  4. @Component
  5. public class JobSchedule implements CommandLineRunner {
  6. @Autowired
  7. private IQuartzService taskService;
  8. /**
  9. * 任务调度开始
  10. * @param strings
  11. * @throws Exception
  12. */
  13. @Override
  14. public void run(String... strings) throws Exception {
  15. System.out.println("任务调度开始==============任务调度开始");
  16. taskService.timingTask();
  17. System.out.println("任务调度结束==============任务调度结束");
  18. }
  19. }

目录结构

(除去了sys_schedule_job表用mybatis plus生成的5个文件)

  1. ├── quartz
  2. ├── job
  3. ├── Job.java
  4. ├── IQuartzService.java
  5. ├── JobOperateEnum.java
  6. ├── JobSchedule.java
  7. ├── QuartzConfig.java
  8. ├── QuartzFactory.java
  9. ├── QuartzServiceImpl.java

以上这些都是基本款,具体实现还要加入执行任务方法类和数据库任务数据



功能实现


静态部分

顾名思义,静态部分就是写一个方法,数据库录入一条数据,当项目启动的时候,就会触发定时任务,等到了时间就会运行。


Job.java
  1. @Component("Job4Log")
  2. public class Job {
  3. public void test() {
  4. System.out.println("-------------------Job4Log任务执行开始-------------------");
  5. System.out.println(new Date().toLocaleString());
  6. System.out.println("-------------------Job4Log任务执行结束-------------------");
  7. }
  8. }

数据库表 sys_schedule_job
idjob_namecron_expressionbean_namemethod_namestatususer_idcreate_timeupdate_timedel_flag
1test job0/2 * * * * ?Job4Logtest012019-08-21 16:07:532019-08-21 16:13:440

效果
  1. -------------------Job任务执行开始-------------------
  2. 2019821 下午4:31:20
  3. -------------------Job任务执行结束-------------------
  4. -------------------Job任务执行开始-------------------
  5. 2019821 下午4:31:22
  6. -------------------Job任务执行结束-------------------
  7. -------------------Job任务执行开始-------------------
  8. 2019821 下午4:31:24
  9. -------------------Job任务执行结束-------------------
  10. -------------------Job任务执行开始-------------------
  11. 2019821 下午4:31:26
  12. -------------------Job任务执行结束-------------------
  13. -------------------Job任务执行开始-------------------
  14. 2019821 下午4:31:28
  15. -------------------Job任务执行结束-------------------
  16. -------------------Job任务执行开始-------------------
  17. 2019821 下午4:31:30
  18. -------------------Job任务执行结束-------------------
  19. -------------------Job任务执行开始-------------------
  20. 2019821 下午4:31:32
  21. -------------------Job任务执行结束-------------------
  22. -------------------Job任务执行开始-------------------
  23. 2019821 下午4:31:34
  24. -------------------Job任务执行结束-------------------
  25. -------------------Job任务执行开始-------------------
  26. 2019821 下午4:31:36
  27. -------------------Job任务执行结束-------------------

动态部分

动态部分就是在静态部分的基础上,加入controller,直接通过接口来实时操作定时任务


ScheduleJobController.java
  1. @PostMapping("addJob")
  2. @ApiOperation("新增定时任务")
  3. @Transactional(rollbackFor = Exception.class)
  4. public R add(@ApiIgnore @RequestAttribute("sysUser") SysUser user, @RequestBody SysScheduleJobForm form) {
  5. SysScheduleJob job = new SysScheduleJob();
  6. job.setJobName(form.getJobName());
  7. job.setCronExpression(form.getCronExpression());
  8. job.setBeanName(form.getBeanName());
  9. job.setMethodName(form.getMethodName());
  10. job.setUserId(user.getId());
  11. job.setStatus(0);
  12. jobService.add(job);
  13. return R.ok();
  14. }
  15. @PostMapping("/startJob")
  16. @ApiOperation("启动定时任务")
  17. public R start(@RequestBody SysScheduleJobIdForm form) {
  18. jobService.start(form.getId());
  19. return R.ok();
  20. }
  21. @PostMapping("/pauseJob")
  22. @ApiOperation("暂停定时任务")
  23. public R pause(@RequestBody SysScheduleJobIdForm form) {
  24. jobService.pause(form.getId());
  25. return R.ok();
  26. }
  27. @PostMapping("/deleteJob")
  28. @ApiOperation("删除定时任务")
  29. public R delete(@RequestBody SysScheduleJobIdForm form) {
  30. jobService.delete(form.getId());
  31. return R.ok();
  32. }
  33. @PostMapping("/startAllJob")
  34. @ApiOperation("开始所有定时任务")
  35. public R startAllJob() {
  36. jobService.startAllJob();
  37. return R.ok();
  38. }
  39. @PostMapping("/pauseAllJob")
  40. @ApiOperation("暂停所有定时任务")
  41. public R pauseAllJob() {
  42. jobService.pauseAllJob();
  43. return R.ok();
  44. }

效果

调用接口:

  1. /scheduleJob/addJob

传入参数:

  1. {
  2. "beanName": "Job",
  3. "cronExpression": "0/2 * * * * ?",
  4. "jobName": "test job",
  5. "methodName": "test"
  6. }

返回参数:

  1. {
  2. "message": "success",
  3. "status": 0
  4. }

控制台输出

  1. -------------------Job任务执行开始-------------------
  2. 2019821 下午5:01:32
  3. -------------------Job任务执行结束-------------------
  4. -------------------Job任务执行开始-------------------
  5. 2019821 下午5:01:34
  6. -------------------Job任务执行结束-------------------
  7. -------------------Job任务执行开始-------------------
  8. 2019821 下午5:01:36
  9. -------------------Job任务执行结束-------------------


CronTrigger配置完整格式:

[秒] [分] [小时] [日] [月] [周] [年]


参数

  1. 秒(0~59)
  2. 分钟(0~59)
  3. 小时(0~23)
  4. 天(0~31,但是你需要考虑你月的天数)
  5. 月(0~11)
  6. 周(1~7)
  7. 年份(1970-2099)(可省略)

例子

  1. 0 0 0/1 * * ? // 每小时执行一次
  2. 0 0 12 * * ? // 每天12点触发
  3. 0 0 22 L * ? // 每月最后一天的22点触发


END