Quartz学习总结

一、基本介绍:

Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目,完全基于 Java 实现。该项目于 2009 年被 Terracotta 收购,目前是 Terracotta 旗下的一个项目。读者可以到 http://www.quartz-scheduler.org/站点下载 Quartz 的发布版本及其源代码。

Quartz 具有以下特点:

1、强大的调度功能,例如支持丰富多样的调度方法,可以满足各种常规及特殊需求;

2、灵活的应用方式,例如支持任务和调度的多种组合方式,支持调度数据的多种存储方式;

3、分布式和集群能力,Terracotta 收购后在原来功能基础上作了进一步提升。

这些总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。 Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。

二、POM引用:

 <dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.3</version>
</dependency>

三、基本结构:

(一)核心元素:

1、Scheduler:一个scheduler的生命周期是有限的,从通过SchedulerFactory创建开始直到调用它的shutdown()方法。scheduler接口一旦创建,就能添加、移除、和列出job和trigger,并执行另一些与调度相关的操作(例如暂停trigger),然而,在scheduler被start()方法启动前,它不会作用于任何trigger(执行job)。。

2、Job: 一个job就是实现了Job接口的类。如下所示,这个接口只有一个简单的方法:execute;

3、JobDetail: JobDetail对象由Quartz客户端(你的程序)在job添加进scheduler的时候创建。这个对象包含了很多job的属性设置,和JobDataMap一样,它能够存储你的job实例的状态信息。JobDetail对象本质上是定义的job实例。

4、Trigger:

(1) trigger对象常常用于触发job的执行(或者触发),当你希望安排一个job,你可以实例化一个trigger,并调整其属性来提供你想要的调度。trigger可能有一个与它们关联的JobDataMap对象。JobDataMap用于传递特定于触发器触发的工作参数。Quartz附带一些不同的触发类型,但是最常用的就是SimpleTrigger和CronTrigger。

(2) SimpleTrigger很方便,如果你需要一次性执行(只是在一个给定时刻执行job),或者如果你需要一个job在一个给定的时间,并让它重复N次,并在执行之间延迟T。

(3) CronTrigger是有用的,如果你想拥有引发基于当前日历时间表,如每个星期五,中午或在每个月的第十天 10:15。

5、JobBuilder: 用于定义/构建已经定义了Job实例的JobDetail实例。

6、TriggerBuilder: 用于定义/构建Trigger实例。

(二)数据表说明:

序号

表名

说明

1

QRTZ_CALENDARS

存储Quartz的Calendar信息

2

QRTZ_CRON_TRIGGERS

存储CronTrigger,包括Cron表达式和时区信息

3

QRTZ_FIRED_TRIGGERS

存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息

4

QRTZ_PAUSED_TRIGGER_GRPS

存储已暂停的Trigger组的信息

5

QRTZ_SCHEDULER_STATE

存储少量的有关Scheduler的状态信息,和别的Scheduler实例

6

QRTZ_LOCKS

存储程序的悲观锁的信息

7

QRTZ_JOB_DETAILS

存储每一个已配置的Job的详细信息

8

QRTZ_SIMPLE_TRIGGERS

存储简单的Trigger,包括重复次数、间隔、以及已触的次数

9

QRTZ_BLOG_TRIGGERS

Trigger作为Blob类型存储

10

QRTZ_TRIGGERS

存储已配置的Trigger的信息

11

QRTZ_SIMPROP_TRIGGERS

(三)关系图:

Quartz学习总结

Quartz 任务调度的核心元素是 scheduler, trigger 和 job,其中 trigger 和 job 是任务调度的元数据, scheduler 是实际执行调度的控制器。

在 Quartz 中,trigger 是用于定义调度时间的元素,即按照什么时间规则去执行任务。Quartz 中主要提供了四种类型的 trigger:SimpleTrigger,CronTirgger,DateIntervalTrigger,和 NthIncludedDayTrigger。这四种 trigger 可以满足企业应用中的绝大部分需求。

在 Quartz 中,job 用于表示被调度的任务。主要有两种类型的 job:无状态的(stateless)和有状态的(stateful)。对于同一个 trigger 来说,有状态的 job 不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。Job 主要有两种属性:volatility 和 durability,其中 volatility 表示任务是否被持久化到数据库存储,而 durability 表示在没有 trigger 关联的时候任务是否被保留。两者都是在值为 true 的时候任务被持久化或保留。一个 job 可以被多个 trigger 关联,但是一个 trigger 只能关联一个 job。

在 Quartz 中, scheduler 由 scheduler 工厂创建:DirectSchedulerFactory 或者 StdSchedulerFactory。 第二种工厂 StdSchedulerFactory 使用较多,因为 DirectSchedulerFactory 使用起来不够方便,需要作许多详细的手工编码设置。 Scheduler 主要有三种:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler。本文以最常用的 StdScheduler 为例讲解。这也是笔者在项目中所使用的 scheduler 类。

线程图:

Quartz学习总结

Scheduler 调度线程主要有两个: 执行常规调度的线程,和执行 misfired trigger 的线程。常规调度线程轮询存储的所有 trigger,如果有需要触发的 trigger,即到达了下一次触发的时间,则从任务执行线程池获取一个空闲线程,执行与该 trigger 关联的任务。Misfire 线程是扫描所有的 trigger,查看是否有 misfired trigger,如果有的话根据 misfire 的策略分别处理。

(四)启动流程:

Quartz学习总结

若quartz是配置在spring中,当服务器启动时,就会装载相关的bean。SchedulerFactoryBean实现了InitializingBean接口,因此在初始化bean的时候,会执行afterPropertiesSet方法,该方法将会调用SchedulerFactory(DirectSchedulerFactory 或者 StdSchedulerFactory,通常用StdSchedulerFactory)创建Scheduler。SchedulerFactory在创建quartzScheduler的过程中,将会读取配置参数,初始化各个组件。

四、简单示例:

 public class HelloJob implements Job {
public HelloJob() {
} public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Hello World! - " + new Date());
}
}
 public class SimpleExample {
public void run() throws Exception {
System.out.println("------- 初始化 ----------------------");
// 首先要实例化scheduler
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
System.out.println("------- 初始化完成 -----------"); // 获取给定时间的下一个完整分钟的时间,例如给定时间 08:13:54 则会反回 08:14:00
Date runTime = DateBuilder.evenMinuteDate(new Date()); System.out.println("------- Job安排 -------------------");
// 获取job实例
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
// 在下一轮分钟触发运行
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startAt(runTime).build();
// 告诉quartz使用某个trigger执行某个job
scheduler.scheduleJob(job, trigger);
System.out.println(job.getKey() + " 将会运行于: " + runTime); // 启动scheduler
scheduler.start(); System.out.println("------- 开始安排 -----------------");
System.out.println("------- 等待65秒 -------------");
Thread.sleep(65L * 1000L); // 关闭scheduler
System.out.println("------- 关闭 ---------------------");
scheduler.shutdown(true);
System.out.println("------- 关闭完成 -----------------");
} public static void main(String[] args) throws Exception {
SimpleExample example = new SimpleExample();
example.run();
}

五、Spring集成:

1、新建spring工程以及maven引入quartz包;

2、application.xml:

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!--
Spring整合Quartz进行配置遵循下面的步骤:
1:定义工作任务的Job
2:定义触发器Trigger,并将触发器与工作任务绑定
3:定义调度器,并将Trigger注册到Scheduler
-->
<!-- 1:定义任务的bean ,这里使用JobDetailFactoryBean,也可以使用MethodInvokingJobDetailFactoryBean ,配置类似-->
<bean name="hwJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 指定job的名称 -->
<property name="name" value="hw_job"/>
<!-- 指定job的分组 -->
<property name="group" value="hw_group"/>
<!-- 指定具体的job类 -->
<property name="jobClass" value="com.dufy.spring.quartz.chapter01.job.HelloWorldJob"/>
<!-- 必须设置为true,如果为false,当没有活动的触发器与之关联时会在调度器中会删除该任务 -->
<property name="durability" value="true"/>
<!-- 指定spring容器的key,如果不设定在job中的jobmap中是获取不到spring容器的 -->
<property name="applicationContextJobDataKey" value="applicationContext"/>
</bean>
<!-- 2.1:定义触发器的bean,定义一个Simple的Trigger,一个触发器只能和一个任务进行绑定 -->
<!-- <bean name="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
指定Trigger的名称
<property name="name" value="hw_trigger"/>
指定Trigger的名称
<property name="group" value="hw_trigger_group"/>
指定Tirgger绑定的Job
<property name="jobDetail" ref="hwJob"/>
指定Trigger的延迟时间 1s后运行
<property name="startDelay" value="1000"/>
指定Trigger的重复间隔 5s
<property name="repeatInterval" value="5000"/>
指定Trigger的重复次数
<property name="repeatCount" value="5"/>
</bean> -->
<!-- 2.2:定义触发器的bean,定义一个Cron的Trigger,一个触发器只能和一个任务进行绑定 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 指定Trigger的名称 -->
<property name="name" value="hw_trigger"/>
<!-- 指定Trigger的名称 -->
<property name="group" value="hw_trigger_group"/>
<!-- 指定Tirgger绑定的Job -->
<property name="jobDetail" ref="hwJob"/>
<!-- 指定Cron 的表达式 ,当前是每隔1s运行一次 -->
<property name="cronExpression" value="0/1 * * * * ?" />
</bean>
<!-- 3.定义调度器,并将Trigger注册到调度器中 -->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<!-- <ref bean="simpleTrigger"/> -->
<ref bean="cronTrigger"/>
</list>
</property>
<!-- <property name="autoStartup" value="true" /> -->
</bean>
<!-- 持久化数据配置,需要添加quartz.properties-->
<bean name="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="applicationContextSchedulerContextKey" value="applicationContextKey"/>
<property name="configLocation" value="classpath:quartz.properties"/>
</bean>
</beans>

3、quartz.properties:

 org.quartz.scheduler.instanceName: dufy_test
org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 2
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true org.quartz.jobStore.misfireThreshold: 60000
#============================================================================
# Configure JobStore
#============================================================================ #default config
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化配置
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties:true #============================================================================
#havent cluster spring
#============================================================================
org.quartz.jobStore.isClustered = false #数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:qzDS #============================================================================
# Configure Datasources
#============================================================================
#JDBC驱动
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/quartz_test
org.quartz.dataSource.qzDS.user:root
org.quartz.dataSource.qzDS.password:root
org.quartz.dataSource.qzDS.maxConnection:10

4、Job类的实现:

 public class HelloWorldJob implements Job{

     private Logger log = LoggerFactory.getLogger(this.getClass());

     public void execute(JobExecutionContext arg0) throws JobExecutionException {
log.info("This is a first spring combine quartz !");
log.info("Welcome to Spring_Quartz World!"+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) );
log.info("Let's begin ! \n \n");
}
}

5、调度程序的实现:

 public class HWTest {
private static Scheduler scheduler; public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring_quartz.xml");
scheduler = (StdScheduler)ac.getBean("scheduler");
startSchedule();
} public static void startSchedule() {
try {
// 1、创建一个JobDetail实例,指定Quartz
JobDetail jobDetail = JobBuilder.newJob(HelloWorldJob.class)
.withIdentity("job1_1", "jGroup1")
// 任务名,任务组
.build();
// 触发器类型
//SimpleScheduleBuilder builder = SimpleScheduleBuilder
// 设置执行次数
//.repeatSecondlyForTotalCount(5);
CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule("0/2 * * * * ?");
// 2、创建Trigger
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1_1", "tGroup1").startNow()
.withSchedule(builder)
.build();
// 3、创建Scheduler
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// 4、调度执行
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}

六、参考资料:

https://www.cnblogs.com/drift-ice/p/3817269.html

https://blog.csdn.net/lkl_csdn/article/details/73613033

https://blog.csdn.net/u010648555/article/details/53363321

https://blog.csdn.net/gjb724332682/article/details/53019953?utm_source=blogkpcl6

上一篇:GCD 深入理解


下一篇:GCD API 理解 (一)