Quartz 框架

145 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

关于quartz框架

大多数应用系统中都需要使用任务调度,基于线程的调度程序开发人员直接编写,不但存在容易出错,实现难度也比较大,所以我们选择使用 Quartz 任务调度开源框架,它提供了强大的任务调度机制,可以更快捷更方便的帮助我们完成调度操作。

Quartz 是一个由 Java 编写的开源任务调度框架,允许开发人员根据时间的间隔来调度任务,该框架实现了任务和触发器的多对多的关系,还能把多个任务与不同的触发器关联。

需要实现任务调度,首先需要明确 3 个概念:任务、触发器、调度器。

  1. 任务 Job

    指在固定时间需要执行的工作内容。Quartz 提供了 Job 接口,来帮助我们定义一个任务。

    Job 接口提供了一个 execute() 方法用于执行具体的任务,需要由 Job 的实现类去实现。

    方法参数类型 JobExecutionContext 对象可以获取调度对象的上下文信息,如任务名称等。

  2. 触发器 Trigger

    任务会在什么时间执行呢?就需要依靠触发器来指定。

    Quartz 提供了 Trigger 接口,用于定义执行任务的时间规则,例如每月的第三天、每天早上 10 点、每周二、四、六下午 6 点等等规则。

    Trigger 提供了两个常用的子接口:SimpleTrigger 和 CronTrigger。

  3. 调度器 Scheduler

    有了任务触发器(即时间规则) 后,我们还需要调度器来将二者关联起来,从而实现 “在规定的时间执行特定的任务”。Quartz 提供了 Scheduler 类来实现调度器,我们可以将任务 Job 对象和触发器 Trigger 对象注册到调度器 Scheduler 中,由调度器来决定任务和触发器的对应关系,即 Scheduler 可以将 Trigger 绑定到一个 Job 上。换句话说,调度器决定了哪个触发器定时执行哪个任务。

Quartz 框架基础程序

Quartz 框架开发准备工作

Quartz 框架相关信息,可以到官网 http://www.quartz-scheduler.org/ 下载。

图片描述

下载的压缩文件进行解压,结构如下:

图片描述

所有的 API 都是在 javadoc 目录下,所需的 jar 包在 lib 目录下,src 目录下是 Quartz 框架的源代码。

首先我们把 Quartz 框架开发的环境进行搭建:

创建 Quartz Maven 工程,工程名QuartzDemo01

然后在 Maven 仓库 https://mvnrepository.com ,查找需要依赖导入的 Quartz jar 包

打开 pom.xml 进行依赖导入 这样 Quartz 框架的开发环境就搭建好了。

使用 SimpleTrigger 实现任务调度

Quartz 框架的核心是任务、触发器和调度器,所有核心的接口和类都是在 org.quartz 包下,我们接下来就一步步来完成。

  1. 任务 Job

    在 目录下创建 FirstJob.java 源文件,编写任务需要做的操作。该类需要实现 Job 接口

    FirstJob 实现 Job 接口,必须实现 execute() 方法,从 JobExecutionContext 参数中可以获取上下文信息,这里我们获取了任务名和触发器名将其打印输出,同时还输出了字符串 Hello Quartz 以及当前系统时间

package org.yamiya;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class FirstJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.print("任务名:" + context.getJobDetail().getKey().getName());
        System.out.println("  触发器名:" + context.getTrigger().getKey().getName());
        System.out.println("Hello Quartz - " + new Date());

    }
}

创建 FirstJobDetail.java 源文件,用于返回 JobDetail 实例


public class FirstJobDetail {
    public static JobDetail getJobDetail(){
        // 获取 JobBuilder 实例,并将任务类注入
        JobBuilder jobbuilder = JobBuilder.newJob(FirstJob.class);
        // 设置任务名和组名
        jobbuilder.withIdentity("job1", "group1");
        // 获取 JobDetail 实例
        JobDetail jd = jobbuilder.build();
        return jd;
    }
}

JobDetail 是一个接口,需要通过 JobBuilder 类来获取它的实例进行操作,首先我们调用 JobBuilder 类中的静态方法 newJob() ,将 MyJob 加载后获取 JobBuilder 实例;获取 JobBuilder 实例后,然后我们可以通过 withIdentity() 方法设置任务名和组名,组名也可以采用默认的方式;最后我们需要调用 build() 方法返回 JobDetail 实例。上述代码为了让大家清楚知道如何获取 JobDetail 实例,所以是分步进行书写,但在实际应用中我们会采用更简洁的方式进行编写,可以这样写:

public static JobDetail getJobDetail(){
  return JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
}
  1. 触发器 Trigger

Trigger 主要是用于触发的时间规则设置,该接口有 2 个子接口 SimpleTrigger 和 CronTrigger,本实验中我们主要是使用 SimpleTrigger 建 FirstTrigger.java 源文件,返回 SimpleTrigger 实例。

import。。

public class FirstTrigger {
    public static SimpleTrigger getSimpleTrigger(){
        // 获取 TriggerBuilder 实例
        TriggerBuilder<Trigger> triggerbuilder = TriggerBuilder.newTrigger();
        // 设置触发器名和组名
        triggerbuilder.withIdentity("trigger1", "group1");
        // 马上触发
        triggerbuilder.startNow();
        // 获取 SimpleScheduleBuilder 实例
        SimpleScheduleBuilder ssbuiler = SimpleScheduleBuilder.simpleSchedule();
        // 每 2 秒执行一次
        ssbuiler.withIntervalInMilliseconds(2000);
        // 一共执行 10 次
        ssbuiler.withRepeatCount(10);
        // 获取 SimpleTrigger 实例
        SimpleTrigger st = triggerbuilder.withSchedule(ssbuiler).build();
        return st;
    }
}

上述代码中,可以看到首先通过 TriggerBuilder 类中的静态方法 newTrigger() 获取 TriggerBuilder 实例,其次通过 withIdentity() 方法设置触发器名和组名,调用 startNow() 表示立即触发;然后通过 SimpleScheduleBuilder 类中的静态方法 simpleSchedule() 获取 SimpleScheduleBuilder 实例,调用 withIntervalInMilliseconds() 和 withRepeatCount() 方法进行触发规则设置,最后通过调用 TriggerBuilder 类中的 withSchedule() 方法将 SimpleScheduleBuilder 实例注入,再调用 build() 完成 SimpleTrigger 实例获取。 同理 SimpleTrigger 我们也可以简化一些来编写,可以这样写:

public static SimpleTrigger getSimpleTrigger(){
    return TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow()
                  .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                                    .withIntervalInMilliseconds(2000)
                                    .withRepeatCount(10)).build();
}
  1. 调度器 Scheduler

Scheduler 需要通过 SchedulerFactory 获取实例,而 SchedulerFactory 有两个实现类 DirectSchedulerFactory 和 StdSchedulerFactory。 创建 FirstScheduler.java 源文件,在该类中将 JobDetail 和 Trigger 进行注册完成调度工作。

import。。。

public class FirstScheduler {

    public void doScheduler() {
        // 通过 SchedulerFactory 获取 Scheduler 实例
        SchedulerFactory factory = new StdSchedulerFactory();
        try {
            Scheduler scheduler = factory.getScheduler();
            // 将 JobDetail 和 Trigger 注册到 Scheduler 中
            scheduler.scheduleJob(FirstJobDetail.getJobDetail(), FirstTrigger.getSimpleTrigger());
            // 启动调度器
            scheduler.start();
            System.out.println("------- Started Scheduler -----------------");
            try {
                Thread.sleep(30 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //关闭调度器,true 表示调度完成后关闭,false 表示强行关闭
            scheduler.shutdown(true);
            System.out.println("------- Shutdown Complete -----------------");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

上述代码中,我们可以看到首先通过 StdSchedulerFactory 类提供的构造器获取 SchedulerFactory 接口实例,其次通过 SchedulerFactory 调用 getScheduler() 方法获取 Scheduler 实例;然后我们就可以调用 Scheduler 接口中的 scheduleJob() 方法将 JobDetail 和 Trigger 实例注册到 Scheduler 中;最后可以调用 start() 启动调度器和 shutdown() 关闭调度器。

  1. test 创建一个测试类 TestQuartz 并添加一个测试方法。
package org.lanqiao;
import org.junit.Test;
public class TestQuartz {
    @Test
    public void test(){
        new FirstScheduler().doScheduler();
    }
}