IT评测·应用市场-qidao123.com

标题: 一文快速入门任务调度框架-Quartz [打印本页]

作者: 冬雨财经    时间: 2023-4-4 14:34
标题: 一文快速入门任务调度框架-Quartz
前言

还不会 Quartz?如果你还没有接触过Quartz,那么你可能错过了一个很棒的任务调度框架!Quartz 提供了一种灵活、可靠的方式来管理和执行定时任务,让咱们的定时任务更加优雅。本篇文章将为你介绍 Quartz 框架的核心概念、API 和实战技巧,让你轻松上手。也不用担心,作为过来人,我会把难懂的概念和术语解释清楚,让你看完本篇文章后,就知道该如何操作 Quartz。当然,本篇文章难免有不足之处,在此欢迎大家指出。那废话少说,下面我们开始吧!
什么是 Quartz?

Quartz:https://github.com/quartz-scheduler/quartz
官网:http://www.quartz-scheduler.org/
Quartz 是一个功能丰富的开源任务调度框架(job scheduling library)。从最小的独立的 Java 应用程序到最大的电子商务系统,它几乎都可以集成。Quartz 可用于创建简单或复杂的调度,以执行数十、数百个甚至数万个任务;这些任务被定义为标准 Java 组件,这些组件可以执行你想让他做的任何事情。Quartz 调度程序包括许多企业级特性,例如支持 JTA 事务(Java Transaction API,简写 JTA)和集群。
注意:Job == 任务
JTA,即 Java Transaction API,JTA 允许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问并且更新数据。
为什么学习 Quartz?

定时任务直接用 Spring 提供的 @Schedule 不行吗?为什么还要学习 Quartz?有什么好处?
是的,一开始我也是这么想的,但是某些场景,单靠 @Schedule 你就实现不了了。
比如我们需要对定时任务进行增删改查,是吧,@Schedule 就实现不了,你不可能每次新增一个定时任务都去手动改代码来添加吧。而 Quartz 就能够实现对任务的增删改查。当然,这只是 Quartz 的好处之一。
Quartz 的特性

运行时环境
任务的调度(Job Scheduling)
当一个触发器(Trigger)触发时,Job 就会被调度执行,触发器就是用来定义何时触发的(也可以说是一个执行计划),可以有以下任意的组合:
Job 由我们自己去命名,也可以组织到命名组(named groups)中。Trigger 也可以被命名并分组,以便在调度器(Scheduler)中更容易地组织它们。
Job 只需在 Scheduler 中添加一次,就可以有多个 Trigger 进行注册。
任务的执行(Job Execution)
任务的持久化(Job Persistence)
事务
集群
监听器和插件
初体验

引入 Quartz 依赖项
创建一个 Spring Boot 项目,然后引入如下依赖,就可以体验 Quartz 了。
  1. <dependency>
  2.     <groupId>org.quartz-scheduler</groupId>
  3.     <artifactId>quartz</artifactId>
  4.     <version>2.3.2</version>
  5. </dependency>
复制代码
示例
现在知道 Quartz 有这么几个概念,分别是 Job、Trigger、Scheduler。在它的设计实现上,分别是 Job 接口、JobDetail 接口、Trigger 接口、Scheduler 接口。除了 Job 接口的实现类需要我们自己去实现,剩下的都由 Quartz 实现了。

Quartz中的调度器(Scheduler)的主要作用就是调度 Job 和 Trigger 的执行。在Quartz中,Job代表需要执行的任务,Trigger代表触发Job执行的条件和规则。调度器会根据Trigger的配置来确定Job的执行时机。
下面的代码包含了一个 Scheduler 的实例对象,接着是调用 start 方法,最后调用 shutdown 方法。
  1. import org.quartz.*;
  2. import org.quartz.impl.StdSchedulerFactory;
  3. public class QuartzTest {
  4.     public static void main(String[] args) {
  5.         try {
  6.             // 从 Factory 中获取 Scheduler 实例
  7.             Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
  8.             // 开始并关闭
  9.             scheduler.start();
  10.             scheduler.shutdown();
  11.         } catch (SchedulerException se) {
  12.             se.printStackTrace();
  13.         }
  14.     }
  15. }
复制代码
一旦我们使用 StdSchedulerFactory.getDefaultScheduler()  获取 Scheduler 对象后,那么程序就会一直运行下去,不会终止,直到我们调用了 scheduler.shutdown() 方法才会停止运行。这是因为获取 Scheduler 对象后,就有许多线程在运行着,所以程序会一直运行下去。
与此同时,控制台会输出相应的日志:
  1. 10:14:02.442 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
  2. 10:14:02.445 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
  3. 10:14:02.452 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
  4. 10:14:02.452 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
  5. 10:14:02.453 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
  6. 10:14:02.453 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  7.   Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  8.   NOT STARTED.
  9.   Currently in standby mode.
  10.   Number of jobs executed: 0
  11.   Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  12.   Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
  13. 10:14:02.453 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
  14. 10:14:02.453 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
复制代码
从日志中也能看出 Quartz 的一些信息,比如版本、使用的线程池、使用的任务存储机制(这里默认是 RAMJobStore)等等信息。
我们想要执行任务的话,就需要把任务的代码放在 scheduler.start() 和 scheduler.shutdown() 之间。
QuartzTest:
  1. import cn.god23bin.demo.quartz.job.HelloJob;
  2. import org.quartz.*;
  3. import org.quartz.impl.StdSchedulerFactory;
  4. // 这里导入了 static,下面才能直接 newJob, newTrigger
  5. import static org.quartz.JobBuilder.newJob;
  6. import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
  7. import static org.quartz.TriggerBuilder.newTrigger;
  8. public class QuartzTest {
  9.     public static void main(String[] args) {
  10.         try {
  11.             // 从 Factory 中获取 Scheduler 实例
  12.             Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
  13.             // 开始并关闭
  14.             scheduler.start();
  15.             // 定义一个 Job(用JobDetail描述的Job),并将这个 Job 绑定到我们写的 HelloJob 这个任务类上
  16.             JobDetail job = newJob(HelloJob.class)
  17.                     .withIdentity("job1", "group1") // 名字为 job1,组为 group1
  18.                     .build();
  19.             // 现在触发任务,让任务执行,然后每5秒重复执行一次
  20.             Trigger trigger = newTrigger()
  21.                     .withIdentity("trigger1", "group1")
  22.                     .startNow()
  23.                     .withSchedule(simpleSchedule()
  24.                             .withIntervalInSeconds(5)
  25.                             .repeatForever())
  26.                     .build();
  27.             // 告知 Quartz 使用我们的 Trigger 去调度这个 Job
  28.             scheduler.scheduleJob(job, trigger);
  29.             // 为了在 shutdown 之前让 Job 有足够的时间被调度执行,所以这里当前线程睡眠30秒
  30.             Thread.sleep(30000);
  31.             scheduler.shutdown();
  32.         } catch (SchedulerException | InterruptedException se) {
  33.             se.printStackTrace();
  34.         }
  35.     }
  36. }
复制代码
HelloJob:实现 Job 接口,重写 execute 方法,实现我们自己的任务逻辑。
  1. import org.quartz.Job;
  2. import org.quartz.JobExecutionContext;
  3. import org.quartz.JobExecutionException;
  4. import java.text.SimpleDateFormat;
  5. public class HelloJob implements Job {
  6.     @Override
  7.     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
  8.         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  9.         System.out.println("Hello Job!!! 时间:" + sdf.format(jobExecutionContext.getFireTime()));
  10.     }
  11. }
复制代码
运行程序,输出如下信息:
  1. 10:25:40.069 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=cn.god23bin.demo.quartz.job.HelloJob
  2. 10:25:40.071 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
  3. 10:25:40.071 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
  4. Hello Job!!! 时间:2023-03-28 10:25:40
  5. 10:25:45.066 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=cn.god23bin.demo.quartz.job.HelloJob
  6. 10:25:45.066 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
  7. 10:25:45.066 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
  8. Hello Job!!! 时间:2023-03-28 10:25:45
  9. # 省略后面输出的信息,都是一样的
复制代码
API 有哪些?

Quartz API 的关键接口如下:
Quartz 涉及到的设计模式:
<ul>Factory Pattern:
  1. // 从 Factory 中获取 Scheduler 实例
  2. Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
复制代码
Builder Pattern:
  1. JobDetail job = newJob(HelloJob.class)
  2.                     .withIdentity("job1", "group1") // 名字为 job1,组为 group1
  3.                     .build();
复制代码
这里的 newJob 方法是 JobBuilder 类中的一个静态方法,就是通过这个来构建 JobDetail 的。
[code]/** * Create a JobBuilder with which to define a JobDetail, * and set the class name of the Job to be executed. *  * @return a new JobBuilder */public static JobBuilder newJob(Class




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4