Quartz简介

原创
2019/10/24 14:32
阅读数 69

 

Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。

 

Quartz核心概念

Job:表示一个工作,要执行的具体内容,此接口中只有一个方法:void execute(JobExecutionContext context)

JobDetail:表示一个具体的可执行的调度程序,Job是这个可执行程序所需要执行的内容,另外,JobDetail还包含了这个任务调度的方案和策略。

Trigger:表示一个调度参数的配置,什么时候去调。

Scheduler:表示一个调度容器,一个调度容器中可以注册多个JobDetail 和 Trigger。

 

Quartz运行环境

Quartz可以运行嵌入在另一个独立式应用程序。

Quartz可以在应用程序服务器(或Servlet容器)内被实例化,并且参与XA事务。

Quartz可以作为一个独立的程序运行(其自己的JVM内),可以通过RMI使用。

Quartz可以被实例化,作为独立的项目集群(负载平衡和故障转移功能),用于作业的执行。

public class Quickstart {
   public static void main(String[] args) {
       try {
           Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
           scheduler.start();
           scheduler.shutdown();
       } catch (SchedulerException e) {
           e.printStackTrace();
       }
   }
}

运行日志如下:

14:53:00.764 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor

14:53:00.790 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main

14:53:00.856 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl

14:53:00.856 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.0 created.

14:53:00.857 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.

14:53:00.858 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.0) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'

 Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.

 NOT STARTED.

 Currently in standby mode.

 Number of jobs executed: 0

 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.

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



14:53:00.858 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'

14:53:00.858 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.0

14:53:00.859 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.

14:53:00.859 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.

14:53:00.859 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.

14:53:00.859 [main] DEBUG org.quartz.simpl.SimpleThreadPool - Shutting down threadpool...

14:53:00.859 [main] DEBUG org.quartz.simpl.SimpleThreadPool - Shutdown of threadpool complete.

14:53:00.859 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

14:53:01.303 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.303 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.304 [DefaultQuartzScheduler_Worker-6] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.304 [DefaultQuartzScheduler_Worker-5] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.305 [DefaultQuartzScheduler_Worker-9] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.323 [DefaultQuartzScheduler_Worker-3] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.338 [DefaultQuartzScheduler_Worker-7] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.338 [DefaultQuartzScheduler_Worker-8] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.338 [DefaultQuartzScheduler_Worker-4] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

14:53:01.338 [DefaultQuartzScheduler_Worker-10] DEBUG org.quartz.simpl.SimpleThreadPool - WorkerThread is shut down.

 

Scheduler的生命周期

从SchedulerFactory创建它时开始,到Scheduler调用shutdown()方法时结束;Scheduler被创建后,可以增加、删除和列举Job和Trigger,以及执行它的与调度相关的操作,但是,Scheduler只有在调用start()方法后,才会真正地触发Trigger(即执行job)。

 

Job和Trigger的联系

一个Job就是实现了Job接口的类,当Job的一个Trigger被触发时,execute()方法由调用程序的一个工作线程调用,传递给execute()方法的JobExecutionContext对象向作业实例提供“运行时”环境,一个Job的Trigger被触发后,execute()方法会被Scheduler的一个工作线程调用,传递给execute()方法的JobExecutionContext对象中保存着该Job运行时的一些信息。

Trigger是用于触发Job执行的,当调度一个Job时,创建一个Trigger实例,设置调度相关的属性,Quartz自带了各种不同类型的Trigger,最常用的主要是SimpleTrigger和CronTrigger。

 

Job和Trigger的Key

将Job和Trigger注册到Scheduler时,可以为它们设置key,配置其身份属性,Job和Trigger的Key可以用于将Job和Trigger放到不同的分组里,然后基于分组进行操作。注意:同一个分组下的Job和Trigger的名称必须唯一,即一个Job或Trigger的Key由名称(name)和分组(group)组成。

 

问题:为什么既有Job又有Trigger呢?

很多任务调度器并不区分Job和Trigger,有些调度器只是简单地通过一个执行时间和一些Job标识符来定义一个Job;其它的一些调度器将Quartz的Job和Trigger对象合二为一。Quartz的开发者认为将调度和要调度的任务分离是合理的,例如:Job被创建后,可以保存在Scheduler中,与Trigger是独立的,同一个Job可以有多个Trigger,Job和Trigger之间是松耦合的,当与Scheduler中的Job关联的Trigger都过期了,可以配置Job稍后被重新调度,而不是重新定义Job,还有,可以修改或者替换Trigger,而不用重新定义与之关联的Job。

 

Job和JobDetail的联系

JobDetail实例是通过JobBuilder类创建的,在Quartz的描述语言中,JobDetail被称为“Job定义”或者“JobDetail实例”,一个正在执行的Job被称为“Job实例”,所以,当我们使用“Job”时,一般指代的是Job定义,或者JobDetail;当我们提到实现Job接口的类时,通常使用“Job类”。

 

Job状态与并发

Job的状态数据和并发性,有一些地方需要注意,在Job类上可以加上一些注解来避免问题:

@DisallowConcurrentExecution:将该注解加到Job类上,告诉Quartz不要并发地执行同一个Job定义,需要注意:该注解虽然加在Job类上,但实际上是作用在JobDetail上的。

@PersistJobDataAfterExecution:将该注解加到Job类上,告诉Quartz在成功执行了job类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该Job(即JobDetail)在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。和 @DisallowConcurrentExecution注解一样,该注解虽然加在Job类上,但实际上是作用在JobDetail上的。

如果你使用了@PersistJobDataAfterExecution注解,我们强烈建议你同时使用@DisallowConcurrentExecution注解,因为当同一个Job(JobDetail)的两个实例被并发执行时,由于竞争,JobDataMap中存储的数据很可能是不确定的。

 

JobDataMap

JobDataMap是Java Map接口的一个实现,可以包含不限量的(序列化的)数据对象,在Job实例执行的时候,可以使用其中的数据。

如果使用持久化的存储机制,在决定JobDataMap中存放什么数据的时候需要小心,因为JobDataMap中存放的对象都会被序列化,因而可能会导致类的版本不一致的问题。

 

JobExecutionException

是execute方法中仅允许抛出一种类型的异常,在实际应用中,应该将execute方法中的所有内容都放到一个”try-catch”块中,以便知道如何来处理发生的异常。

 

快速开始的完整示例

public class Quickstart {

   public static void main(String[] args) {
       try {
           Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
           scheduler.start();
           JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1")
                   .usingJobData("name", "quartz").build();
           Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow()
                   .withSchedule(simpleSchedule().withIntervalInSeconds(30).repeatForever()).build();

           scheduler.scheduleJob(job, trigger);
           try {
               Thread.sleep(1000L * 60L * 10L);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           scheduler.shutdown();
       } catch (SchedulerException e) {
           e.printStackTrace();
       }
   }
}

public class HelloJob implements Job {
   @Override
   public void execute(JobExecutionContext context) throws JobExecutionException {
       try {
           JobDetail job = context.getJobDetail();
           String name = job.getJobDataMap().getString("name");
           System.out.println("hello " + name + " at " + new Date());
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

 

参考资料

1、Quartz官方文档:https://www.w3cschool.cn/quartz_doc/

2、Quartz官网:http://www.quartz-scheduler.org/

3、Quartz使用总结:https://www.cnblogs.com/drift-ice/p/3817269.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部