SpringBoot3集成Quartz

简介: Quartz由Java编写的功能丰富的开源作业调度框架,可以集成到几乎任何Java应用程序中,并且能够创建多个作业调度;

标签:Quartz.Job.Scheduler;

一、简介

Quartz由Java编写的功能丰富的开源作业调度框架,可以集成到几乎任何Java应用程序中,并且能够创建多个作业调度;

在实际的业务中,有很多场景依赖定时任务,比如常见的:订单超时处理,数据报表统计分析,会员等周期性管理,业务识别和预警通知等;

二、工程搭建

1、工程结构

1.png

2、依赖管理

starter-quartz组件中,实际依赖的是quartz组件2.3.2版本,使用Quartz框架时,需要自定义任务和执行逻辑,以更加灵活的方式管理业务调度;

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
    <version>${spring-boot.version}</version>
</dependency>

3、数据库

Quartz框架使用的表结构在如图的路径下,本文选择MySQL数据库存储,除此之外自定义两张表:quartz_job任务表和quartz_log任务执行日志表;

2.png

4、配置文件

在配置文件中使用Druid组件连接boot-quartz数据库,对于Quartz框架,主要配置数据库存储,调度器的基础信息,以及执行任务的线程池;

spring:
  # 定时器配置
  quartz:
    # 使用数据库存储
    job-store-type: jdbc
    # 初始化完成后自动启动调度程序
    autoStartup: true
    properties:
      org:
        quartz:
          # 调度器配置
          scheduler:
            instanceName: bootQuartzScheduler
            instanceId: AUTO
          # 存储配置
          jobStore:
            class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            tablePrefix: qrtz_
            isClustered: true
            misfireThreshold: 12000
            clusterCheckinInterval: 15000
            useProperties: false
          # 线程池配置
          threadPool:
            threadNamePrefix: Boot_Job_Pool
            threadPriority: 5
            threadCount: 10
            class: org.quartz.simpl.SimpleThreadPool

三、Quartz用法

对于任务管理的相关Web接口,采用Swagger文档组件,接口和实体类添加注解后,访问IP:Port/swagger-ui/index.html地址即可;

3.png

1、初始化加载

在服务启动时执行init初始化方法,查询quartz_job表中运行和暂停状态的任务,判断触发器是否存在,如果不存在则创建,如果存在则更新;

@Service
public class QuartzJobService {
   
   

    @Resource
    private QuartzJobMapper quartzJobMapper ;
    @Resource
    private QuartzManage quartzManage;

    @PostConstruct
    public void init () {
   
   
        LambdaQueryWrapper<QuartzJob> queryWrapper = new LambdaQueryWrapper<>() ;
        queryWrapper.in(QuartzJob::getState,JobState.JOB_RUN.getStatus(),JobState.JOB_STOP.getStatus());
        List<QuartzJob> jobList = quartzJobMapper.selectList(queryWrapper);
        jobList.forEach(quartzJob -> {
   
   
            CronTrigger cronTrigger = quartzManage.getCronTrigger(quartzJob.getId()) ;
            if (Objects.isNull(cronTrigger)){
   
   
                quartzManage.createJob(quartzJob);
            } else {
   
   
                quartzManage.updateJob(quartzJob);
            }
        });
    }
}

2、新增任务

在创建任务时,需要定义JobKeyTriggerKey的构建规则,Key需要具备唯一性,通常使用任务表的主键ID,任务一般是基于Cron表达式被调度执行的;

@Component
public class QuartzManage {
   
   

    @Resource
    private Scheduler scheduler ;

    public void createJob (QuartzJob quartzJob){
   
   
        try {
   
   
            // 构建任务
            JobDetail jobDetail = JobBuilder.newJob(QuartzRecord.class).withIdentity(getJobKey(quartzJob.getId())).build() ;
            // 构建Cron调度器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                                                .cronSchedule(quartzJob.getCronExpres())
                                                .withMisfireHandlingInstructionDoNothing() ;
            // 任务触发器
            CronTrigger trigger = TriggerBuilder.newTrigger()
                                                .withIdentity(getTriggerKey(quartzJob.getId()))
                                                .withSchedule(scheduleBuilder).build() ;
            jobDetail.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY,quartzJob);
            scheduler.scheduleJob(jobDetail,trigger) ;
            // 状态校验
            checkStop(quartzJob) ;
        } catch (SchedulerException e){
   
   
            throw new RuntimeException("createJob Fail",e) ;
        }
    }
}

3、更新任务

先通过任务ID查询TriggerKey,对于更新来说,最常见的就是Cron表达式即调度规则的更新,或者任务的执行参数更新;

@Component
public class QuartzManage {
   
   

    @Resource
    private Scheduler scheduler ;

    public void updateJob(QuartzJob quartzJob) {
   
   
        try {
   
   
            // 查询触发器Key
            TriggerKey triggerKey = getTriggerKey(quartzJob.getId());
            // 构建Cron调度器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
                                                .cronSchedule(quartzJob.getCronExpres())
                                                .withMisfireHandlingInstructionDoNothing();
            // 任务触发器
            CronTrigger trigger = getCronTrigger(quartzJob.getId())
                                .getTriggerBuilder().withIdentity(triggerKey)
                                .withSchedule(scheduleBuilder).build();
            trigger.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, quartzJob);
            scheduler.rescheduleJob(triggerKey, trigger);
            // 状态校验
            checkStop(quartzJob) ;
        } catch (SchedulerException e) {
   
   
            throw new RuntimeException("updateJob Fail",e) ;
        }
    }
}

4、暂停任务

先通过任务ID查询JobKey,判断任务是非运行状态,则停止任务;

@Component
public class QuartzManage {
   
   

    @Resource
    private Scheduler scheduler ;

    public void checkStop (QuartzJob quartzJob){
   
   
        try {
   
   
            if(quartzJob.getState() != JobState.JOB_RUN.getStatus()){
   
   
                this.scheduler.pauseJob(getJobKey(quartzJob.getId()));
            }
        } catch (SchedulerException e){
   
   
            throw new RuntimeException("pauseJob Fail",e) ;
        }
    }

}

5、恢复任务

先通过任务ID查询JobKey,恢复任务正常执行;

@Component
public class QuartzManage {
   
   

    @Resource
    private Scheduler scheduler ;

    public void resumeJob (Integer jobId){
   
   
        try {
   
   
            this.scheduler.resumeJob(getJobKey(jobId));
        } catch (SchedulerException e){
   
   
            throw new RuntimeException("resumeJob Fail",e) ;
        }
    }
}

6、执行一次

传入任务主体,再通过任务ID查询JobKey,然后立即执行一次任务;

@Component
public class QuartzManage {
   
   

    @Resource
    private Scheduler scheduler ;

    public void run (QuartzJob quartzJob){
   
   
        try {
   
   
            JobDataMap dataMap = new JobDataMap() ;
            dataMap.put(QuartzJob.JOB_PARAM_KEY,quartzJob);
            this.scheduler.triggerJob(getJobKey(quartzJob.getId()),dataMap);
        } catch (SchedulerException e){
   
   
            throw new RuntimeException("run Fail",e) ;
        }
    }
}

7、删除任务

先通过任务ID查询JobKey,彻底删除任务;

@Component
public class QuartzManage {
   
   

    @Resource
    private Scheduler scheduler ;

    public void deleteJob (Integer jobId){
   
   
        try {
   
   
            scheduler.deleteJob(getJobKey(jobId));
        } catch (SchedulerException e){
   
   
            throw new RuntimeException("deleteJob Fail",e) ;
        }
    }
}

8、任务执行

Quartz被集成在Spring框架之后,任务类自然会以Bean对象的方式被管理,在任务创建时,设置要执行的作业类QuartzRecord,该类继承QuartzJobBean抽象类,通过重写executeInternal方法,来管理任务实际执行的逻辑;

public class QuartzRecord extends QuartzJobBean {
   
   
    @Override
    protected void executeInternal(JobExecutionContext context) {
   
   
        QuartzJob quartzJob = (QuartzJob)context.getMergedJobDataMap().get(QuartzJob.JOB_PARAM_KEY) ;
        QuartzLogService quartzLogService = (QuartzLogService)SpringContextUtil.getBean("quartzLogService") ;
        // 定时器日志记录
        QuartzLog quartzLog = new QuartzLog () ;
        quartzLog.setJobId(quartzJob.getId());
        quartzLog.setBeanName(quartzJob.getBeanName());
        quartzLog.setParams(quartzJob.getParams());
        quartzLog.setCreateTime(new Date());
        long beginTime = System.currentTimeMillis() ;
        try {
   
   
            // 加载并执行
            Object target = SpringContextUtil.getBean(quartzJob.getBeanName());
            Method method = target.getClass().getDeclaredMethod("run", String.class);
            method.invoke(target, quartzJob.getParams());
            long executeTime = System.currentTimeMillis() - beginTime;
            quartzLog.setTimes((int)executeTime);
            quartzLog.setState(LogState.LOG_SUS.getStatus());
        } catch (Exception e){
   
   
            // 异常信息
            long executeTime = System.currentTimeMillis() - beginTime;
            quartzLog.setTimes((int)executeTime);
            quartzLog.setState(LogState.LOG_FAIL.getStatus());
            quartzLog.setError(e.getMessage());
        } finally {
   
   
            // 保存执行日志
            quartzLogService.insert(quartzLog) ;
        }
    }
}

四、参考源码

文档仓库:
https://gitee.com/cicadasmile/butte-java-note

源码仓库:
https://gitee.com/cicadasmile/butte-spring-parent
相关文章
|
1月前
|
存储 Java 调度
Sppring集成Quartz简单案例详解 包括(添加、停止、恢复、删除任务、获取下次执行时间等)
Sppring集成Quartz简单案例详解 包括(添加、停止、恢复、删除任务、获取下次执行时间等)
33 2
|
4月前
|
Java 关系型数据库 MySQL
SpringBoot 集成 Quartz + MySQL
SpringBoot 集成 Quartz + MySQL
126 1
|
6月前
|
SQL API 调度
Springboot2.4.5集成Quartz实现动态任务数据持久化-不怕重启服务
Springboot2.4.5集成Quartz实现动态任务数据持久化-不怕重启服务
280 0
|
6月前
|
Java API 调度
Web后端Javaee企业级开发之定时任务 Springboot整合任务框架Quartz和Task详解
Web后端Javaee企业级开发之定时任务 Springboot整合任务框架Quartz和Task详解
93 0
|
7月前
|
存储 数据可视化 安全
Java全套智慧校园系统源码springboot+elmentui +Quartz可视化校园管理平台系统源码 建设智慧校园的5大关键技术
智慧校园指的是以物联网为基础的智慧化的校园工作、学习和生活一体化环境,这个一体化环境以各种应用服务系统为载体,将教学、科研、管理和校园生活进行充分融合。无处不在的网络学习、融合创新的网络科研、透明高效的校务治理、丰富多彩的校园文化、方便周到的校园生活。简而言之,“要做一个安全、稳定、环保、节能的校园。
126 6
|
7月前
|
Java Spring 容器
SpringBoot 使用Quartz执行定时任务对象时无法注入Bean问题
SpringBoot 使用Quartz执行定时任务对象时无法注入Bean问题
286 1
|
7月前
|
存储 NoSQL Java
【十】springboot整合quartz实现定时任务优化
【十】springboot整合quartz实现定时任务优化
125 0
|
7月前
|
SQL Java 调度
SpringBoot集成quartz定时任务trigger_state状态ERROR解决办法
SpringBoot集成quartz定时任务trigger_state状态ERROR解决办法
|
7月前
|
XML Java API
Spring Boot 整合 Quartz 实现 Java 定时任务的动态配置
Spring Boot 整合 Quartz 实现 Java 定时任务的动态配置
204 0
|
7月前
|
SQL 分布式计算 Java
SpringBoot集成quartz调度linkis任务
SpringBoot集成quartz调度linkis任务