springboot-Quartz定时任务并持久化

发布时间 2023-06-16 15:11:33作者: mingruqi

新建项目,添加依赖

新建一个springboot项目,勾选下springboot,以及quartz依赖

 或者我们可以直接在pom.xml文件中直接添加依赖

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

添加完成依赖运行下项目我们就可以看到quartz已经加载进来了

 此时我们还没有进行持久化到数据库,所以看到的任务调度是放在内存中的

Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

创建具体执行类
接下来新建一个工作类QuartzSchedulerJob.java

继承下QuartzJobBean,并重写下里面的方法executeInternal

这里面我们可以写一些这些代码处理的逻辑,比如根据不同的JobDetail执行不同的处理,或者根据设置不同的JobData去调用不同的参数的处理逻辑,根据个人不同的需要,也可以建立多个具体工作类,在后期设置的定时任务的时候根据不同的需要配置不同的具体工作类就好了。

package com.example.demoquartz;
 
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
 
import java.time.LocalDateTime;
 
public class QuartzSchedulerJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        switch (jobExecutionContext.getJobDetail().getKey().getGroup()) {
            case "动物组":
                System.out.println("定时任务动物组工作:" + jobExecutionContext.getJobDetail().getKey().getName()
                        + " 当前时间:" + LocalDateTime.now());
                break;
            case "机器人组":
                System.out.println("定时任务机器人组工作:" + jobExecutionContext.getJobDetail().getKey().getName()
                        + " 当前时间:" + LocalDateTime.now());
                break;
        }
 
    }
}

创建/实现定时任务接口

新建一个定时任务的接口SystemSchedulerService.java

package com.example.demoquartz.service;
 
public interface SystemSchedulerService {
    /**
     * 添加
     *
     * @param name
     * @param group
     * @param cron
     * @return
     */
    boolean addScheduler(String name, String group, String cron);
 
    /**
     * 修改
     *
     * @param jobDetailName
     * @param jobDetailGroup
     * @param cron
     * @return
     */
    boolean updateScheduler(String jobDetailName, String jobDetailGroup, String cron);
 
    /**
     * 删除
     *
     * @param jobDetailName
     * @param jobDetailGroup
     * @return
     */
    boolean deleteScheduler(String jobDetailName, String jobDetailGroup);
 
    /**
     * 暂停
     *
     * @param jobDetailName
     * @param jobDetailGroup
     * @return
     */
    boolean puaseScheduler(String jobDetailName, String jobDetailGroup);
 
    /**
     * 恢复
     *
     * @param jobDetailName
     * @param jobDetailGroup
     * @return
     */
    boolean resumeScheduler(String jobDetailName, String jobDetailGroup);
}

新建一个实现类SystemSchedulerServiceImpl.java

任务调度我们直接装配

    @Autowired
    Scheduler scheduler;

在此贴上在线Cron表达式生成链接:在线Cron表达式生成链接

package com.example.demoquartz.service;
 
import com.example.demoquartz.QuartzSchedulerJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service
public class SystemSchedulerServiceImpl implements SystemSchedulerService {
    @Autowired
    Scheduler scheduler;
 
    @Override
    public boolean addScheduler(String name, String group, String cron) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(QuartzSchedulerJob.class)//绑定一个具体工作类
                    .withIdentity(name, group) //设置一个标识,分组以及名字
                    .usingJobData("jobData", name) //传递到具体工作的数据,可以多个,获取根据dataKey获取即可
                    .usingJobData("executeData", "测试")
                    .build();
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(name, group)//设置一个触发器标识,这里设置了跟JobDetail使用一样的命名以及分组
                    .forJob(jobDetail)//绑定trigger到jobdetail
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
            return true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
    }
 
    @Override
    public boolean updateScheduler(String jobDetailName, String jobDetailGroup, String cron) {
        try {
            JobKey jobKey = JobKey.jobKey(jobDetailName, jobDetailGroup);
            if (!CronExpression.isValidExpression(cron) || !scheduler.checkExists(jobKey)) {
                return false;
            }
            //triggerKey为添加定时任务时配置的name,group,这里是添加的时候设置的name跟group跟jobdetail是一样的
            TriggerKey triggerKey = TriggerKey.triggerKey(jobDetailName, jobDetailGroup);
            Trigger newTrigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
 
//            CronTrigger newTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
//            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
 
            scheduler.rescheduleJob(triggerKey, newTrigger);
            return true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
    }
 
    @Override
    public boolean deleteScheduler(String jobDetailName, String jobDetailGroup) {
        try {
            JobKey jobKey = JobKey.jobKey(jobDetailName, jobDetailGroup);
            if (!scheduler.checkExists(jobKey)) {
                return false;
            }
            scheduler.deleteJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
    }
 
    @Override
    public boolean puaseScheduler(String jobDetailName, String jobDetailGroup) {
        try {
            JobKey jobKey = JobKey.jobKey(jobDetailName, jobDetailGroup);
            if (!scheduler.checkExists(jobKey)) {
                return false;
            }
            scheduler.pauseJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
    }
 
    @Override
    public boolean resumeScheduler(String jobDetailName, String jobDetailGroup) {
        try {
            JobKey jobKey = JobKey.jobKey(jobDetailName, jobDetailGroup);
            if (!scheduler.checkExists(jobKey)) {
                return false;
            }
            scheduler.resumeJob(jobKey);
            return true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            return false;
        }
    }
}

创建初始化类
接口定义好了,接下来我们想要在项目启动完成就自动给我们添加一些设置好的定时任务

下面新建个SystemSchedulerInit.java,添加下注解@Configuration

实现接口ApplicationRunner,实现里面的run方法,

我们在项目启动完成就添加两个定时任务。

package com.example.demoquartz;
 
import com.example.demoquartz.service.SystemSchedulerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class SystemSchedulerInit implements ApplicationRunner {
    @Autowired
    SystemSchedulerService systemSchedulerService;
 
    @Override
    public void run(ApplicationArguments args) throws Exception {
        systemSchedulerService.addScheduler("小猪佩奇", "动物组", "0/5 * * * * ?");
        systemSchedulerService.addScheduler("阿童木", "机器人组", "0/5 * * * * ?");
 
    }
}

最后在入口类里面添加下注解@EnableScheduling

package com.example.demoquartz;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication
@EnableScheduling
public class DemoQuartzApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(DemoQuartzApplication.class, args);
    }
 
}

启动项目,这时我们就可以看到定时任务已经打印在控制台了

 

创建动态更新接口

接下来我们实现下动态更新定时任务

新建TestController.java

package com.example.demoquartz;
 
import com.example.demoquartz.service.SystemSchedulerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class TestController {
    @Autowired
    SystemSchedulerService systemSchedulerService;
 
    @PostMapping("/add")
    public boolean add(@RequestParam String name, @RequestParam String group, @RequestParam String cron) {
        return systemSchedulerService.addScheduler(name, group, cron);
    }
 
    @PostMapping("/update")
    public boolean update(@RequestParam String name, @RequestParam String group, @RequestParam String cron) {
        return systemSchedulerService.updateScheduler(name, group, cron);
    }
 
    @PostMapping("/delete")
    public boolean delete(@RequestParam String name, @RequestParam String group) {
        return systemSchedulerService.deleteScheduler(name, group);
    }
}

启动postman或者直接打开浏览器

请求添加接口

localhost:8088/add?name=蟹老板&group=动物组&cron=0/5 * * * * ?

 

 请求下更新接口

localhost:8088/update?name=阿童木&group=机器人组&cron=0/1 * * * * ?

 此时定时任务就变成每秒执行一次了

 请求删除接口

localhost:8088/delete?name=阿童木&group=机器人组

 

 

定时任务持久化
当前定时任务保存在内存中,每当项目重启的时候,定时任务就会清空并重写加载,原来的一些执行信息就丢失了,我们需要在保存下定时任务的执行信息,下次重启项目的时候我们的定时任务就可以根据上次执行的状态再执行下一次的定时任务。

持久化首先要链接数据库

在pom.xml中添加下数据库链接依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

在application.properties下添加

#数据库链接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/testdemo
#quartz配置
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=always
spring.quartz.scheduler-name=testScheduler

其中

spring.quartz.job-store-type=jdbc 是设置quartz的存储方式可以选memory或者jdbc。
spring.quartz.jdbc.initialize-schema=always 是设置每次启动项目是否重建表结构,并且清空里面的数据,有三个选项可以选择always,never,embedded。

选择never也可以自己手动建表,只需要官网把包下载下来在里面找到相应的数据库的sql文件即可

官网地址

进入官网地址,选择下载就好了,选择自己想要的版本

解压压缩包

在路径中就可以找到相应的sql文件,要是找不到可以搜sql,就会把所有包含sql的文件找出来了

quartz-2.4.0-SNAPSHOT\src\org\quartz\impl\jdbcjobstore

 

执行下语句就可以生成相应的表了,这里演示是直接使用always设置,实际项目中最好是手动建表或者是配置文件第一次加载时设置成always,后面设置成never。

以上是最简单的配置,如果需要集群或者其他配置,可以搜索下其他大神的案例或者在官网文档中搜索自己所需配置。

官网配置地址:官网配置选项地址

 

 

 其中配置

spring.quartz.scheduler-name=testScheduler

相当于

spring.quartz.properties.org.quartz.scheduler.instanceName = testScheduler

若是两个都写上,项目会优先执行spring.quartz.scheduler-name=testScheduler

自定义调度名称

 

配置文件可以直接写在application.properties或者新建quartz.yml或者quartz.properties

演示是直接使用application.properties

配置好重启项目,刷新数据库即可看到配置的信息已经存在数据库里面,这时项目启动时自装配任务部分代码SystemSchedulerInit.java就可以注释掉了。

  最后贴上一个中文的quartz入门站点,有需要的可以去查看下:Quartz快速入门指南


————————————————
版权声明:本文为CSDN博主「FunctionTwo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhizexiaoyao/article/details/118597042