如何使用Springboot & Quartz进行任务调度

本文介绍如何在SpringBoot2项目中整合Quartz任务调度框架,实现动态改变cron表达式的功能,并提供了一种最佳实践思路,包括配置示例、自定义任务表结构以及通过API进行任务管理的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我们常见的业务场景难免会遇到需要做定时任务的功能,一般Springboot自带的定时功能可以满足corn表达式不变的定时任务,但是当我们想动态改变corn表达式的时候,就可以用到开源任务调度框架—Quartz。

Springboot2整合Quartz

pom依赖

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

yml配置

spring:
  quartz:
    #相关属性配置
    properties:
      org:
        quartz:
          scheduler:
            instanceName: quartzScheduler
            instanceId: AUTO
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true

最佳实践思路

不采用在数据库生成Quartz的二十几表,那样数据库显得比较臃肿,直接采用Quartz在内存中记录每条定时任务的状态,然后只用创建一张任务表存储任务。在程序每次启动的时候,去读取任务表,加载到调度器上面即可。

任务表

-- flowable.quartz_job definition

CREATE TABLE `quartz_job` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '编号',
  `job_name` varchar(50) NOT NULL COMMENT '任务名称',
  `job_group` varchar(50) NOT NULL COMMENT '任务组别',
  `job_class_name` varchar(100) NOT NULL COMMENT '任务目标执行class',
  `cron_expression` varchar(100) NOT NULL COMMENT 'cron表达式',
  `trigger_state` varchar(15) NOT NULL COMMENT '触发器状态',
  `old_job_name` varchar(50) NOT NULL COMMENT '旧的名称',
  `old_job_group` varchar(50) NOT NULL COMMENT '旧的组别',
  `description` varchar(100) NOT NULL COMMENT '描述',
  PRIMARY KEY (`id`),
  UNIQUE KEY `un_group_name` (`job_group`,`job_name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='任务表';

使用调度器API

package org.tegic.spring.activity.service.impl;

import java.util.List;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.tegic.spring.activity.common.Result;
import org.tegic.spring.activity.dao.JobMapper;
import org.tegic.spring.activity.entity.QuartzJob;
import org.tegic.spring.activity.enums.JobStatus;
import org.tegic.spring.activity.service.IJobService;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

@Service
public class JobServiceImpl implements IJobService {

    private static final String TRIGGER_IDENTITY = "trigger";

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private JobMapper jobMapper;

    @Override
    public PageInfo<QuartzJob> listQuartzJob(String jobName, Integer pageNo, Integer pageSize) {
        PageHelper.startPage(pageNo, pageSize);
        List<QuartzJob> jobList = jobMapper.listJob(jobName);
        PageInfo<QuartzJob> pageInfo = new PageInfo<QuartzJob>(jobList);
        return pageInfo;
    }

    // 保存任务
    @Override
    public Result saveJob(QuartzJob quartz) {
        try {
            schedulerJob(quartz);

            quartz.setTriggerState(JobStatus.RUNNING.getStatus());
            quartz.setOldJobGroup(quartz.getJobGroup());
            quartz.setOldJobName(quartz.getJobName());
            jobMapper.saveJob(quartz);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    // 触发任务,只执行一次
    @Override
    public Result triggerJob(String jobName, String jobGroup) {
        JobKey key = new JobKey(jobName, jobGroup);
        try {
            scheduler.triggerJob(key);
        } catch (SchedulerException e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    // 暂停任务
    @Override
    public Result pauseJob(String jobName, String jobGroup) {
        JobKey key = new JobKey(jobName, jobGroup);
        try {
            scheduler.pauseJob(key);
            jobMapper.updateJobStatus(jobName, jobGroup, JobStatus.PAUSED.getStatus());
        } catch (SchedulerException e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    // 恢复任务
    @Override
    public Result resumeJob(String jobName, String jobGroup) {
        JobKey key = new JobKey(jobName, jobGroup);
        try {
            scheduler.resumeJob(key);
            jobMapper.updateJobStatus(jobName, jobGroup, JobStatus.RUNNING.getStatus());
        } catch (SchedulerException e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    // 删掉任务

    @Override
    public Result removeJob(String jobName, String jobGroup) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(TRIGGER_IDENTITY + jobName, jobGroup);
            scheduler.pauseTrigger(triggerKey); // 停止触发器
            scheduler.unscheduleJob(triggerKey); // 移除触发器
            scheduler.deleteJob(JobKey.jobKey(jobName, jobGroup)); // 删除任务
            jobMapper.removeQuartzJob(jobName, jobGroup);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    // 获取任务

    @Override
    public QuartzJob getJob(String jobName, String jobGroup) {
        return jobMapper.getJob(jobName, jobGroup);
    }

    // 更新任务

    @Override
    public Result updateJob(QuartzJob quartz) {
        try {
            scheduler.deleteJob(new JobKey(quartz.getOldJobName(), quartz.getOldJobGroup()));
            schedulerJob(quartz);
            quartz.setOldJobGroup(quartz.getJobGroup());
            quartz.setOldJobName(quartz.getJobName());
            jobMapper.updateJob(quartz);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error();
        }
        return Result.ok();
    }

    // 将任务绑定到调度器上

    @Override
    public void schedulerJob(QuartzJob job) throws Exception {
        // 构建job信息
        Class cls = Class.forName(job.getJobClassName());
        // cls.newInstance(); // 检验类是否存在
        JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(job.getJobName(), job.getJobGroup())
                .withDescription(job.getDescription()).build();

        // 触发时间点
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression().trim());
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(TRIGGER_IDENTITY + job.getJobName(), job.getJobGroup()).startNow()
                .withSchedule(cronScheduleBuilder).build();
        // 交由Scheduler安排触发
        scheduler.scheduleJob(jobDetail, trigger);

    }
}

实现CommandLineRunner类,重写run方法,启动的时候就去加载定时任务。

private void loadJobToQuartz() throws Exception {
		List<QuartzJob> jobs = jobMapper.listJob("");
		for (QuartzJob job : jobs) {
			jobService.schedulerJob(job);
			if (JobStatus.PAUSED.getStatus().equals(job.getTriggerState())) {
				scheduler.pauseJob(new JobKey(job.getJobName(), job.getJobGroup()));
			}
		}
	}

到此配置基本完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十万芙特

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值