Quartz - 任务调度框架整合使用

前言

项目中遇到一个,需要 客户自定任务启动时间 的需求。原来一直都是在项目里硬编码一些定时器,所以没有学习过。

很多开源的项目管理框架都已经做了 Quartz 的集成。我们居然连这么常用得东西居然没有做成模块化,实在是不应该。


Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。但是相较于Timer, Quartz增加了很多功能:

  • 持久性作业 - 就是保持调度定时的状态;
  • 作业管理 - 对调度作业进行有效的管理;

官方文档:Documentation (quartz-scheduler.org)Quartz Enterprise Job Scheduler 2.3.0 API

这一篇先记一下基础使用、springboot 内的使用,以及灵活配置方式。


基础使用

Quartz 的核心类有以下三部分:

  • 任务 Job :需要实现的任务类,实现 execute() 方法,执行后完成任务。
  • 触发器 Trigger :包括 SimpleTrigger 和 CronTrigger。
  • 调度器 Scheduler :任务调度器,负责基于 Trigger触发器,来执行 Job任务。

主要关系如下:

image-20211001220627545


Demo

按照官网的 Demo,搭建一个纯 maven 项目,添加依赖:

<!-- 核心包 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>
<!-- 工具包 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.3.0</version>
</dependency>

新建一个任务,实现了 org.quartz.Job 接口:

public class MyJob implements Job {
   
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
   
        System.out.println("任务被执行了。。。");
    }
}

main 方法,创建调度器、jobDetail 实例、trigger 实例、执行:

public static void main(String[] args) throws Exception {
   
    // 1.创建调度器 Scheduler
    SchedulerFactory factory = new StdSchedulerFactory();
    Scheduler scheduler = factory.getScheduler();

    // 2.创建JobDetail实例,并与MyJob类绑定(Job执行内容)
    JobDetail job = JobBuilder.newJob(MyJob.class)
        .withIdentity("job1", "group1")
        .build();

    // 3.构建Trigger实例,每隔30s执行一次
    Trigger trigger = TriggerBuilder.newTrigger()
        .withIdentity("trigger1", "group1")
        .startNow()
        .withSchedule(simpleSchedule()
                      .withIntervalInSeconds(30)
                      .repeatForever())
        .build();

    // 4.执行,开启调度器
    scheduler.scheduleJob(job, trigger);
    System.out.println(System.currentTimeMillis());
    scheduler.start();

    //主线程睡眠1分钟,然后关闭调度器
    TimeUnit.MINUTES.sleep(1);
    scheduler.shutdown();
    System.out.println(System.currentTimeMillis());
}

日志打印情况:

image-20211001233107007


JobDetail

JobDetail 的作用是绑定 Job,是一个任务实例,它为 Job 添加了许多扩展参数。

主要字段 涵义、作用
name 任务名称
group 任务分组,默认分组 DEFAULT
jobClass 任务类,就是上面 Demo 中的 MyJob 的路径
jobDataMap 任务参数信息。JobDetail、Trigger 都可以使用 JobDataMap 来设置一些参数或信息。

每次Scheduler调度执行一个Job的时候,首先会拿到对应的Job,然后创建该Job实例,再去执行Job中的execute()的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。

为什么设计成JobDetail + Job,不直接使用Job?

JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中。

这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。

而JobDetail & Job 方式,Sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以 规避并发访问 的问题。


JobExecutionContext

  • 当 Scheduler 调用一个 job,就会将 JobExecutionContext 传递给 Job 的 execute() 方法;
  • Job 能通过 JobExecutionContext 对象访问到 Quartz 运行时候的环境以及 Job 本身的明细数据。

任务实现的 execute() 方法,可以通过 context 参数获取。

public interface Job {
   
    void execute(JobExecutionContext context)
        throws JobExecutionException;
}

在 Builder 建造过程中,可以使用如下方法:

usingJobData("tiggerDataMap", "测试传参")

在 execute 方法中获取:

context.getTrigger().getJobDataMap().get("tiggerDataMap");
context.getJobDetail().getJobDataMap().get("tiggerDataMap");

Job 状态参数

有状态的 job 可以理解为多次 job调用期间可以持有一些状态信息,这些状态信息存储在 JobDataMap 中。

而默认的无状态 job,每次调用时都会创建一个新的 JobDataMap。

示例如下:

//多次调用 Job 的时候,将参数保留在 JobDataMap
@PersistJobDataAfterExecution
public class JobStatus implements Job {
   
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
   
        long count = (long) context.getJobDetail().getJobDataMap().get("count");
        System.out.println("当前执行,第" + count + "次");
        context.getJobDetail().getJobDataMap().put("count", ++count);
    }
}
JobDetail job = JobBuilder.newJob(JobStatus.class)
                .withIdentity("statusJob", "group1")
                .usingJobData("count", 1L)
                .build();

输出结果:

当前执行,第1次
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
当前执行,第2次
当前执行,第3次

Trigger

定时启动/关闭

Trigger 可以设置任务的开始结束时间, Scheduler 会根据参数进行触发。

Calendar instance = Calendar.getInstance();
Date startTime = instance.getTime();
instance.add(Calendar.MINUTE, 1);
Date endTime = instance.getTime();

// 3.构建Trigger实例
Trigger trigger = TriggerBuilder.newTrigger()
    .withIdentity("trigger1", "group1")
    // 开始时间
    .startAt(startTime)
    // 结束时间
    .endAt(endTime)
    .build();

在 job 中也能拿到对应的时间,并进行业务判断

public void execute(JobExecutionContext context) throws JobExecutionException {
   
    System.out.println("任务执行。。。");
    System.out.println(context.getTrigger().getStartTime());
    System.out.println(context.getTrigger().getEndTime());
}

运行结果:

[main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.0
1633149326723
任务执行。。。
Sat Oct 02 12:35:26 CST 2021
Sat Oct 02 12:36:26 CST 2021
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.

SimpleTrigger

这是比较简单的一类触发器,用它能实现很多基础的应用。使用它的主要场景包括:

  1. 在指定时间段内,执行一次任务

最基础的 Trigger 不设置循环,设置开始时间。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
quartz框架是一个开源的Java调度框架,可用于编写定时任务。而Spring Boot是一个用于简化Java应用开发的框架。在将quartz框架与Spring Boot整合时,我们可以通过使用new的方式来编写定时任务。 首先,在Spring Boot的主配置类上加上@EnableScheduling注解,以启用定时任务的支持。然后,我们可以创建一个新的类并实现org.springframework.scheduling.annotation.SchedulingConfigurer接口,这个接口提供了定时任务的配置信息。在该类中,我们可以使用@Bean注解来定义一个定时任务,并设置其触发时间、逻辑等。 在定义定时任务的方法上,我们可以使用@Scheduled注解来指定任务的执行方式和触发时间。例如,可以使用@Scheduled(fixedRate = 5000)来表示每隔5秒执行一次该任务,或者使用@Scheduled(cron = "0 0 12 * * ?")来表示每天中午12点执行一次任务。 需要注意的是,在使用new的方式编写定时任务时,我们需要手动将该任务注册到quartz框架中。我们可以在Spring Boot的配置类中通过创建org.springframework.scheduling.quartz.SchedulerFactoryBean对象来获取一个Quartz调度器实例。然后,再使用调度器实例的scheduleJob方法来注册定时任务。 总的来说,通过new的方式编写定时任务的步骤如下: 1. 在Spring Boot的主配置类上加上@EnableScheduling注解,启用定时任务的支持。 2. 创建一个新的类并实现SchedulingConfigurer接口,用于配置定时任务。 3. 在配置类中定义定时任务的方法,并使用@Scheduled注解指定任务的执行方式和触发时间。 4. 在配置类中获取Quartz调度器实例,并使用调度器实例的scheduleJob方法来注册定时任务。 这样,我们就可以使用new的方式编写定时任务,并实现quartz框架与Spring Boot的整合

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值