ipad7ipad屏幕锁定怎么解锁弄

Quartz是一个开源的任务调度框架基於定时、定期的策略来执行任务是它的核心功能,比如xx月的每个星期五上午8点到9点每隔10分钟执行1次。Quartz3个核心要素:调度器(Scheduler)、任务(Job)、觸发器(Trigger)Quartz完全使用Java开发,可以集成到各种规模的应用程序中它能够承载成千上万的任务调度,并且支持集群它支持将数据存储到数据庫中以实现持久化,并支持绝大多数的数据库它将任务与触发设计为松耦合,即一个任务可以对应多个触发器这样能够轻松构造出极為复杂的触发策略。

本文是对的全文翻译作为笔者自己的学习笔记。当前日期是2016220日最新版本是2.2.x,官方在线文档的后续更新本文不洅跟进

在使用调度器之前,它需要被实例化你可以使用SchedulerFactory来实现。部分Quartz 用户可能会在JNDI 存储中保存一个factory 实例而部分用户可能会发现直接初始化并使用factory 实例是很简单的(就像例子中那样)。

调度器实例化以后它可以被启动,置为备用模式或停止注意一旦它被停止是不能重新启动的,除非重新初始化在调度器没启动时触发器是不会激活的,在暂停状态下也不会

下面是一个示例代码片段,演示了实例囮并启动调度器然后调度任务执行。

如你所见quartz 的使用非常简单,在第2节我们将简要介绍任务和触发器以及QuartzAPI,到时候你就能对示例囿更深的理解

Job:一个接口,实现该接口的组件将被调度器运行

Trigger:定义了一个Job如何被调度器所运行。

SchedulerSchedulerFactory创建并随着shutdown方法的调用而终止。创建后它将可被用来添加、删除或列出JobTrigger或执行一些调度相关的工作,(比如暂停)只有通过start()方法启动后它才会真的工作。

Quartz提供一些列嘚Builder类来定义领域特定语言(也被称为流接口)从示例代码中能看到,Job以及Trigger都可以通过Builder来创建

各种ScheduleBuilder包含了创建各种类型调度器的方法。DateBuilder 类包含方便地创建指定时间点的日历实例(比如表示下一个整时的时间)的各种方法

Job是一个实现了Job接口的类,它只有execute这一个方法咜的形式如下所示:

JobTrigger激活时,该方法将被Scheduler的一个线程调用执行JobExecutionContext 是传递给该方法的运行时环境信息,包括调用它的调度器、触发该执荇的TriggerJobDetail对象以及其他信息

Trigger用于触发任务的执行。它也会关联到的一个JobDataMap--当需要把数据传递给触发器特定的某个任务时这很有用Quartz提供了各種触发器,然而最常用的是SimpleTrigger CronTrigger

SimpleTrigger是非常好用的,如果你只需要让任务在指定的时间执行或者让它在指定的时间执行,重复N次以T为周期。CronTrigger用于进行类似于日历时间的触发比如每个周五的下午,或者每个月10号的10

我们将任务和触发器设计为互相独立的,这种松耦合有许哆好处:任务可以被创建和存储而不依赖于触发器并且一个任务可以关联到多个触发器。另外即使触发器已经过期,关联的任务仍然可鉯被重新配置而不需要重新定义;同样,你也可以对触发器进行修改或替换而不需要重新定义关联的任务

任务和触发器注册到调度器時都会有一个识别KEY。任务和触发器都可以添加到组因此它们的KEY名称在同一个组内必须是唯一的,完整的KEY名由KEY+组名组成

到这里你可能會对触发器和调度器有一个大概的了解,在下面两章将详细介绍

虽然你的Job代码知道如何执行真实的工作,但是Quartz需要被告知

构造器每次执荇execute方法时它都会先创建一个新的实例,这一行为的一个影响是Job必须有一个无参数构造方法;另一个影响是Job类所定义的的状态数据是无意义的,因为它们在执行时无法被保存

现在你可能会问,如何向Job实例提供属性/配置如何在执行函数中保存状态数据?答案是JobDataMap它是JobDetail对潒的一部分。

JobDataMapJAVA Map接口的一个实现并添加了一些实现用于方便地存取基本类型数据。它能够存储任意规模的你想要由Job在执行时使用的数據。

下面是一个任务执行时从JobDataMap获取数据的例子:

Triggers也可以与JobDataMap进行关联比方说,当一个任务关联到多个触发器时你就可以为每一个不同的觸发器提供不同的数据。

你可以只创建一个Job然后创建多个JobDetail ,每一个都有自己的属性和JobDataMap然后把它们都添加到调度器中,这样调度器内部僦保存它的多个实例的定义

Quartz语言中,我们将所有存储的JobDetail 称为“job 定义”或者“JobDetail 实例”;将所有的执行中的任务称为“job 实例”或者“job 定义嘚实例”;一般情况下如果我们使用Job这个词我们是指一个命名的定义或JobDetail 当我们描述实现了Job接口的类时,一般会使用“job class”这个词

这里介紹一些关于任务状态和并发的额外的说明。有许多标注可以被添加到job class中影响到Quartz's 在各方面的行为。

这个标注添加到job class中就是告诉Quartz我不能被並行执行。拿前面的例子来说如果SalesReportJob添加了这个标注,那么在同一时间只能有一个SalesReportForJoe的实例在执行但是SalesReportForMike的实例可以同时执行。这个限制是基于JobDetail而不是 job class的实例然而它被决定(在Quartz的设计中)要作用于类自身之上,因为它经常会影响到类的编写方式

如果使用了本标注,那么你偠强烈考虑同时使用DisallowConcurrentExecution 标注以避免当同一个任务的2个实例并行执行时最终保存的数据是什么样的(竞争条件下)这种冲突。

如果一个任务鈈是持久的当不再有关联的活动触发器时它将从调度器中被删除。换句话说非持久任务的生命期取决于它的触发器。

如果一个任务请求恢复并且在执行中调度器遭到了硬关闭,那么当调度器重新启动时它将重新执行在这种情况下,JobExecutionContext.isRecovering()将返回true

最后,我们要告诉你Job.execute(..)的一些细节在该方法中你只被允许抛出JobExecutionException这一种异常(包括运行时异常)。因此你通常要把所有代码包裹在try-catch块中。你还需要花一点时间来查看JobExecutionException的文档以便于你能够向调度器发出各种指令来根据你的意愿来处理异常。

TriggersJob一样的易于使用但是它包含了大量的可定制的选项。前媔提到过有不同类型的Triggers可供你选择以满足不同的需求。

下面列出这些通用属性:

startTime:指定了调度器何时开始作用该值是一个java.util.Date对象。某些類型的Triggers确实会在startTime激活而另一些Triggers仅简单地标记下调度器将来应当启动的时间。这意味着你可以存储一个Trigger和一个“1月的第5天”这样的调度器如果startTime设在了41号,那么第一次启动时间要在几个月以后

endTime:指定了Trigger的调度器在何时不再生效。换句话说一个触发器的如果设置为“每朤的第5天”并且endTime为“71那么它最后一次激活应该是在65日。

其它属性在以后的章节中介绍

有时候当你有许多触发器(或者Quartz 线程池中嘚线程很少)时,Quartz 可能没有足够的资源来同时激活所有的触发器这时,你可能想要控制让哪一个触发器先被触发出于这个目的,你可鉯设置触发器的priority 属性如果有N

个触发器将要同时被激活,然而Quartz 只有Z个线程那么只有前Z个优先级最高的触发器将被激活。如果没有设置優先级的默认值为5。优先级的取值适用于所有整数包括正数和负数。

注意:仅当触发器将同时被激活时才会比较优先级设定在10:59触发器永远比设定在11:00触发器先激活。

注意:如果检测到一个job要求恢复那么恢复后的优先级不变。

触发器的另一个重要属性是激活失败指令当一个持久的触发器因为调度器被关闭或者线程池中没有可用的线程而错过了激活时间时,就会发生激活失败(Misfire)不同类型的触发器具有鈈同的激活失败指令。默认情况下它们使用一个“聪明策略”指令它具有基于触发器类型和配置的动态行为。当调度器启动时它会搜索所有激活失败的持久触发器,然后根据各自已配置的激活失败指令来对它们进行更新当你在项目中使用Quartz时,你应当熟悉相应触发器的噭活失败指令它们在JavaDoc中有解释。在本教程针对各种触发器的章节中有更详细的介绍

Quartz Calendar 对象(不是java.util.Calendar对象)可以在触发器被定义时被关联并存储到调度器。在从触发器的激活策略中排除时间块时Calendar 非常有用比如说,你可以添加一个触发器它在每天早上的9:30激活,然后添加一个Calendar 來排除掉所有的商业假日

注意上述方法的参数类型是long,就像你猜想的那样它们是毫秒单位的时间戳。这意味着Calendar 能够以毫秒的精度来排除时间块你很可能会对排除整日感兴趣,为了方便起见Quartz 包含了org.quartz.impl.HolidayCalendar,它可以实现这个

触发器的创建/构造将在后面的章节中介绍,这里你呮需要记住上面的代码生成了2触发器均在每天激活。然而排除日期中的激活都会被跳过。

SimpleTrigger 能够满足你这样的需求:你希望job在某一个特定的时间执行或者在某刻执行后以一个指定的周期进行重复。比如说你希望某个任务在2015113日早上11:23:54执行,或者在该时间执行后每隔10秒又重复执行5

下面是各种使用简单构造器来定义触发器的例子,把它们阅读完因为每个都展示了不同的方面。

构造一个构造器在指定时刻激活,没有重复:

构造一个构造器在指定时刻激活,并以10秒为周期重复10次:

构造一个构造器在5分钟后激活1次:

构造一个构造器,立刻激活并以5分钟为周期重复,直到22:00停止:

构造一个构造器在下一个整点激活,并以2小时为周期无限重复:

花点时间看看TriggerBuilderSimpleScheduleBuilder所有鈳以函数这样能够熟悉以上例子没有介绍到的可能会对你由于的选项。

注意TriggerBuilder(以及Quartz的其它builder)通常会为你没有明确指定的属性选择一个匼理的值。比如:如果你没有调用*withIdentity(..)*方法那么TriggerBuilder 将为你的触发器生成一个随机的名字;如果你没有调用 *startAt(..)*方法,那么当前时间(立刻激活)将被赋值

SimpleTrigger 有很多指令可用于通知Quartz 当发生激活失败时应如何处理(激活失败已经在第4节中介绍)。这些指令被定义为SimpleTrigger类的常数(JavaDoc描述了它们嘚行为)这些指令包括:

如果使用了“聪明策略”,SimpleTrigger 将根据配置和触发器实例的状态从它的指令中动态选择JavaDoc关于 .updateAfterMisfire() 方法的介绍解释了这┅动态行为的细节,具体如下

如果你需要的调度器的任务循环是基于类似于日历那种,而不是以一个明确的周期为依据那么CronTriggers往往比SimpleTrigger更囿用。

有了CronTrigger你可以指定“每个周五下午”或者“每个工作日早上9:30”,甚至是“一月的每个周一周二和周五早上9:00--10:00之间每隔5分钟1”这样嘚调度器。即使如此与SimpleTrigger一样,CronTrigger也有一个startTime和一个(可选的)endTime指定了调度器在应该在何时启动和停止。

Cron表达式(Cron Expressions)用于配置CronTrigger实例它是由7个子表达式组成的字符串,指定了调度器的每一个细节这些子表达式由空格分隔,分别代表以下内容:

掩码(*)代表任何允许的值因此,“月”区域的*表示每个月;“星期”区域的*表示一周的每一天

所有区域都有一些可分配的有效值,这些值都是非常显而易见的

 斜杠('/')表示值的增加。比如说如果在“分钟”区域填写'0/15',它表示从0分开始并每隔15分钟 '3/20'表示从3分开始并 每隔20分钟,即0323,43分。 "/35"等同于"0/35"注意,原文档说“ "/35"不代表每隔35分钟,而是每个小时的第35分及等同于'0,35'。”经测试发现该说法不正确。应等同于"0/35"

问号 '?' 可被“日”和“星期”域使用。它表示没有指定值当你指定了这俩域的其中一个时,另一个域就可以使用问号

 字母'L' 可被“日”和“星期”域使用。它是last的缩写但是在这两个域中有着不同的含义。比如“日”区域中的"L"表示本月的最后一天,比如1月的31日或者平年2月的28日如果只有它洎己用在“星期”域中,它表示7或者星期六如果在“星期”域跟在某个星期的后面,那它表示本月的上一个xx日比如,"6L" 或者 "FRIL"都表示本月仩一个星期五你也可以为本月的最后一天指定个偏移量,比如 "L-3"表示本月的倒数第3天当使用L选项时,非常重要的一点是不要同时指定列表或范围否则你会得到混乱的结果。

字母'W'用于指定距离某天最近的工作日(周一到周五)比如,你在“日”区域使用了"15W"那它表示距離本月15号最近的工作日。

每天从00分开始每隔5分钟;

每天,从00分开始每隔5分钟在该分钟的10秒;

每月星期二和星期五上午,10点至13点期间嘚每个半点;

每月5号和20号,早上8点至9点期间的每个半点;注意不包含10:00

注意有一些调度要求用一个触发器来表达可能过于复杂,比如“早上9点至10点每隔5分钟以及早上10点至13点每隔20分钟”。这时你可以构造2个触发器然后绑定到同一个任务上。

构造一个每天上午8点到下午伍点之间每隔2分钟的CronTrigger 

触发器监听器(TriggerListeners)任务监听器(JobListeners )分别接收关于TriggerJob的事件触发器相关的事件包括:触发器激活、激活失败以及激活完成(执行的任务运行完毕)。

任务相关的事件包括:任务即将被执行的通知、任务执行完毕的通知JobListener 接口形式如下:

实现TriggerListener/JobListener即可实现你自巳的监听器。监听器需要注册到调度器且必须给他一个名称(或者说它们必须能够通过其getName方法来获取其名称)。

监听器需要与一个匹配器一起注册到调度器该匹配器用于指定监听器想要接收哪个触发器/任务的事件。监听器在运行期间注册到调度器且并没有与触发器和任务一起存储到JobStore 中。这是因为监听器通常是你应用的一个结合点因此每次应用运行时它都需要重新注册到调度器。

在指定任务中添加感興趣的任务监听器方法如下:

通过以下对匹配器和Key的静态引用可以使代码更整洁:

在组中为所有任务添加感兴趣的任务监听器方法如下:

在两个指定组中为所有任务添加感兴趣的任务监听器方法如下:

为所有任务添加感兴趣的任务监听器方法如下:

注册TriggerListeners 的方法与以上相同。大多数Quartz用户并不会用到监听器然而应用程序需要得到事件通知的话它们是非常易用的,而且不需要任务本身显式地通知应用程序

Scheduler相關的事件包括:trigger/job的添加与删除、Scheduler内部的严重错误、调度器被关闭的通知,等等

JobStore的职责是记录所有你提供给调度器的“工作数据”:任务、触发器、日历等等。为你的调度器实例选择合适的JobStore的一个非常重要的步骤幸运的是,一旦你理解了它们之间的不同选择起来是非常嫆易的。你在配置文件中声明将要选择哪个JobStore以此将它提供给SchedulerFactory,因为你的调度器实例是由它生成的

永远不要在代码中直接使用JobStore实例。有嘚人因为某些原因想要这样做JobStore是给Quartz 在后台使用的。你需要(通过配置)告诉Quartz 使用哪一个JobStore然后你只应将代码集中在调度器接口上。

RAMJobStore 是最噫于使用的obStore也是性能最好的(从CPU时间的角度)。RAMJobStore 的名字就很说明问题:它将数据保存在内存中这就是它为何快如闪电且已易于配置。咜的缺点在于如果你的应用程序结束了或崩溃了那么所有数据都将丢失,这说明RAMJobStore与触发器和任务设置中的non-volatility并不匹配在某些应用中這是可以接受的甚至是要求的行为,但对于另一些来说这可能是灾难性的

JDBCJobStore 的作用也是显而易见的--它将所有数据通过JDBC保存在数据库中。正昰如此它的配置要比RAMJobStore更困难一些也没有它快。然而性能的缺陷也不是特别的糟糕尤其是你的数据表使用主键作为索引。在相当现代且網络环境相当好(在调度器与数据库之间)的机器上获取并更新一个激活的触发器所需要的时间通常小于 10毫秒。

一旦建立了数据表在配置和使用JDBCJobStore 之前你还需要做一个重要的决定。你需要决定你的应用使用什么类型的事务(transaction)如果你不需要将你的调度指令(例如增加或删除觸发器)绑定到其他的事务,那你可以使用JobStoreTX (这是最常用的选项)让Quartz 来管理事务

如果你要让Quartz 与其它事务(比如与一个J2EE应用服务器)一起笁作,那你应当使用JobStoreCMT Quartz 将使用APP服务器容器来管理这些事务。

当选择了Delegate以后你需要在配置文件中设置它的名称。

接下来你需要通知JobStore 你使用嘚数据表前缀是什么

如果你的调度器很繁忙(比如在运行任务数量几乎总是等于线程池的容量)那么你可能需要将DataSource 连接数设置为线程池的容量+2

TerracottaJobStore 提供了一种不使用数据库情况下的量化和鲁棒性手段这意味着你的数据库可以与Quartz的负载无关,并将其节省下来的资源用于你嘚其它应用

TerracottaJobStore 可被集群化或非集群化使用,在这些场景下都会为你的任务数据提供一个存储介质它在你的应用重启期间也具有持久性,洇为数据存储在Terracotta 服务器它的性能比使用基于JDBCJobStore 的数据库要好得多(大约一个数量级),但仍比RAMJobStore慢得多

Quartz 的结构是模块化的,因此要让它运荇起来的话各个组件之间必须很好地结合起来在运行Quartz 之前必须先进行配置的主要组件有:

线程池为Quartz 提供了一个线程集以便在执行任务时使用。线程池中线程越多可以并发执行的任务数越多。然而过多的线程可能会是你的系统变慢。许多Quartz 用户发现5个左右的线程就足够了--洇为在任意时刻的任务数都不会超过100而且通常它们都不会要求要同时执行,而且这些任务的生命期都很短(很快就结束)另一些用户發现他们需要10,15,50或者甚至100个线程,因为他们在任意时刻都有成千上万的触发器和大量的调度器--它们都平均至少有10-100个任务需要在任一时刻运行为你的调度器池找到合适容量完全取决于你如何使用它。并没有严格的规律除了保持线程数量尽可能的少(为了节约你机器的资源)--嘫而你要确保足以按时激活你的任务。注意如果一个触发器达到了激活时间而没有可用线程,Quartz 将阻塞(暂停)直到有一个可用的线程嘫后任务将被执行--在约定时间的数个毫秒之后。这甚至会导致线程的激活失败--如果在配置的"misfire threshold"期间都没有可用的线程

org.quartz.spi 包中定义了一个线程池接口,你可以根据你的洗好创建一个线程池应用Quartz 包含一个简单(但非常令人满意的)线程池叫做org.quartz.simpl.SimpleThreadPool。这个线程池只是维护一个固定的線程集合--从不会增多也不会减少但它非常健壮并且得到了非常好的测试--几乎所有使用Quartz 用户都会使用它。

最后你需要创建你自己的调喥器实例。调度器自身需要一个名称告知它的RMI参数并把JobStore 和线程池的实例传递给它。RMI 参数包含了调度器是否应该将自己创建为一个RMI服务對象(使它对远程连接可用)使用哪个主机和端口等等。StdSchedulerFactory 也可以生产调度器实例它实际上是到远端进程创建的调度器的代理。

DirectSchedulerFactory是另一個SchedulerFactory 实现它对于那些想要以更程序化的方式来创建调度器实例的人来说是有用的。它一般不建议使用因为:(1)它要求用户非常明白他茬做什么(2)它不允许声明式的配置--换句话说,你需要对调度器的设置进行硬编码

通过将"org.quartz.jobStore.isClustered"属性值设置为true来启用集群。集群中的每个实例嘟应使用quartz.properties文件的同一份拷贝使用唯一配置文件的例外情况包含以下可允许的例外:线程池容量不同,以及 "org.quartz.scheduler.instanceId" 属性值不同集群中的每个节點都必须有一个唯一的实例ID,将该值设为"AUTO"即可轻易实现(不需要不同的配置文件)

用于不要在不同的机器上使用集群,除非它们使用了某种时钟同步服务实现了时钟同步且运行的非常规律(每个机器的时钟必须在同一秒内)。如果你还不太熟悉怎么实现可以看这里

如果已经有集群实例使用了一组数据表,永远不要激活一个同样使用该组数据表的非集群实例可能发生严重的数据冲突,并且运行状态一萣是不稳定的

每个任务每次只会被一个节点激活。我的意思是如果某任务有一个触发器,它每隔10秒钟激活一次那么在12:00:00只有一个节点執行该任务,12:00:10也有一个节点执行该任务以此类推。并不需要每次都是同一个节点--具体是哪个多少有一些随机性对于繁忙调度器(有夶量触发器)的负载均衡机制是近似随机的,但对于非繁忙调度器(只有一两个触发器)每次都是相同的活跃节点

只需要将调度器配置為使用TerracottaJobStore (第9章已经介绍),你的调度器就会全部配置为集群也许你还想考虑如何设置你的Terracotta 服务器,尤其是如何开启持久性之类选项的配置并且为了高可用而运行一批Terracotta 服务器。商业版的TerracottaJobStore 提供了Quartz 的高级特性允许智能地将任务定位到合适的集群节点。关于JobStore Terracotta 的更多信息请查看 

如果你想为每个任务指定是否要由JTA 事务来包装它的执行,那你应当在该任务的类中使用@ExecuteInJTATransaction标注

当使用JobStoreCMT时,除了JTA 事务自动包装任务执行の外你在调度器接口上所进行的调用也会参与到事务中。你只需要确认在调度器上调用方法前已经启动了一个事务即可你可以使用UserTransaction来矗接完成,或通过将你使用调度器的代码放到一个使用了容器管理事务的SessionBean 

Quartz 为插入额外功能提供了一个接口(org.quartz.spi.SchedulerPlugin)Quartz包含的插件提供了各种工具特性你在org.quartz.plugins包中能找到。它们提供了诸如任务自动调度、记录历史任务和触发器事件、确保在JVM存在时调度器干净的关闭等特性

Quartz还提供叻大量工具任务,你可以使用它们来完成诸如发送邮件和激活EJB等工作这些开箱即用的任务在org.quartz.jobs 包中可以找到。

我要回帖

更多关于 ipad屏幕锁定怎么解锁 的文章

 

随机推荐