在上一章中,你首次尝试使用了 Quartz 来部署 Job。无可否认地,那些 Job 都不是很复杂,但这个不是重点。你应该轻松的对如何构造并部署 Job 有了相当的了解,更重要的是,由此热情的希望学得更多的东西。在本章中将会继续给你讲述。

第四章将带领你深入到 Quart 框架的核心部分。可证明的是,这一章对于阅读和理解本书是非常之重要的。调度器(Scheduler) 是此框架的心脏。本章关注于如何使用 Scheduler 来管理你的 Job;如何创建并关联触发器以使 Job 能被触发执行;以及如可选择 calendar 为给定的时程安排提供更多的灵活性。

此刻,什么也没发生,下一刻,仍旧什么也没发生。

道格拉斯.亚当斯,《银河系漫游指南》

1. Quartz 调度器

Quartz 框架包含许多的类和接口,它们分布在大概 11 个包中。多数你所要使用到的类或接口放置在 org.quartz 包中。这个包含盖了 Quartz 框架的公有 API.

我们不打算对这个框架的所有类和接口都面面俱到。而所要介绍的是那些有助于你理解 Quartz 如何做它该做事情的组件的子集。图 4.1 展示了一个只留下必要的调度器的精简类图。

Quartz 类图(仅显示主要组件)

Scheduler 是 Quartz 的主要 API。对于 Quartz 用户来说,多数时候与框架的交互是发生于 Scheduler  之上的。客服端与 Scheduler 交互是通过 org.quartz.Scheduler 接口的。这个 Scheduler 的实现,在这种情况下,是一个代理,对其中方法调用会传递到 QuartzScheduler 实例上。QuartzScheduler 对于客户端是不可见的,并且也不存在与此实例的直接交互。

QuartzScheduler 处在框架根的位置,它是一个引擎驱动着整个框架。并非所有的功能都直接内建到 QuartzScheduler,然而,框架为灵活性和可配置性考虑而设计,所以许多重要的功能由分离的组件和子框架实现。这就意味着 Quartz 用户可以用自己某个关键特征实现来替换原有默认实现。即使 QuartzScheduler 代理了它的一些职责,但它仍然掌控着整个作业调度流程。

·Quartz Scheduler 类层次

客户端会同两种类型的 Scheduler 交互,如图 4.2. 它们都实现了 org.quartz.Scheduler 接口。

org.quartz.Scheduler 类层次

作为一个 Quartz 用户,你要与实现了 org.quartz.Scheduler 接口的类交互。在你调用它的任何 API 之前,你需要知道如何创建一个 Scheduler 的实例。

2. Quartz SchedulerFactory

尽管你已使用到了 Scheduler 类型了,但你未曾显式的去创建 Scheduler 的实例。取而代之的是用了某个工厂方法来确保了构造出 Sheduler 实例并正确的得到初始化。(工厂设计模式之所以谓之工厂模式是因为它承担了生产对象的职责。在这里是生产了一个 Scheduler 实例) Quartz 框架为这一目的提供了 org.quartz.SchedulerFactory 接口。角色 SchedulerFactory 就是用来产生 Scheduler 实例的。当 Scheduler 实例被创建之后,就会存到一个仓库中(org.quartz.impl.SchedulerRepository),这个仓库还提供了通过一个 class loader 查询实例的机制。要使用 Scheduler 实例,客户端必须从工厂(和随同的仓库中)使用不同方法调用来获取到它们。换句话说,要通过工厂创建一个 Scheduler 实例并获取到它需要经由两次方法调用。有一些方便的方法封装了那两个方法,你将很快能看到。

你可使用两种不同类型的 SchedulerFactory 来创建 Scheduler 实例 (看图 4.3)

所有的 Scheduler 实例应该由 SchedulerFactory 来创建

这两个 Scheduler 工厂分别是 org.quartz.impl.DirectoSchedulerFactory 和 org.quartz.impl.StdSchedulerFactory. 让我们来逐个检视它们。

·使用 DirectSchedulerFactory

DirectSchedulerFactory 是为那些想绝对控制 Scheduler 实例是如何生产出的人所设计的。代码 4.1 显示了最简单的方式去使用 DirectSchedulerFactory 来创建一个 Scheduler 实例。

代码 4.1. 使用 DirectSchedulerFactory

  1. public class Listing_4_1 {
  2. static Log logger = LogFactory.getLog(Listing_4_1.class);
  3. public static void main(String[] args) {
  4. Listing_4_1 example = new Listing_4_1();
  5. example.startScheduler();
  6. }
  7. public void startScheduler() {
  8. DirectSchedulerFactory factory=DirectSchedulerFactory.getInstance();
  9. try {
  10. // Initialize the Scheduler Factory with 10 threads
  11. factory.createVolatileScheduler(10);
  12. // Get a scheduler from the factory
  13. Scheduler scheduler = factory.getScheduler();
  14. // Start the scheduler running
  15. logger.info("Scheduler starting up...");
  16. scheduler.start();
  17. } catch (SchedulerException ex) {
  18. logger.error(ex);
  19. }
  20. }
  21. }

public class Listing_4_1 { static Log logger = LogFactory.getLog(Listing_4_1.class); public static void main(String[] args) { Listing_4_1 example = new Listing_4_1(); example.startScheduler(); } public void startScheduler() { DirectSchedulerFactory factory=DirectSchedulerFactory.getInstance(); try { // Initialize the Scheduler Factory with 10 threads factory.createVolatileScheduler(10); // Get a scheduler from the factory Scheduler scheduler = factory.getScheduler(); // Start the scheduler running logger.info("Scheduler starting up..."); scheduler.start(); } catch (SchedulerException ex) { logger.error(ex); } } }

当使用 DirectSchedulerFactory 时,有三个基本的步骤。首先,你必须用静态方法 getInstance() 获取到工厂的实例。当你持有了工厂的实例之后,你必须调用其中的一个 createXXX 方法去初始化它。如代码 4.1 所示例子中是调用 createVolatileScheduler() 方法告诉工厂以十个工作者线程初始化它自己(至于工作者线程的更多内容将在本章的后部分讨论到)。第三步也就是最后一步是通过工厂的 getScheduler() 方法拿到 Scheduler 的实例。

在调用 getScheduler() 方法之后调用其中的一个 createXXX 方法
方法 createVolatileScheduler() 方法不会返回 scheduler 的实例。createXXX() 方法是告诉工厂如何配置要创建的 Scheduler 实例。你必须调用方法 getScheduler() 获取到在工厂上执行方法 createXXX() 产生的实例。实际上,在调用 getScheduler() 方法之前,你必须调用其中一个 createXXX() 方法;否则,你将有收到一个 SchedulerException 错误,因为根本没有 Scheduler 实例存在。

你可从数个不同的 createXXX() 方法中选择,依赖于你想要的 Scheduler 类型和你需要怎样的配置。代码 4.1 中用的是 createVolatileScheduler() 方法创建 Scheduler 实例的。方法 createVolatileScheduler() 带有单个参数:要创建的线程数量。在图 4.2 中,你已看到还有一个 RemoteScheduler 类。你必须要用一个不同的 createXXX() 方法去创建 RemoteScheduler 实例。有两个版本的方法可用:

  1. public void createRemoteScheduler(String rmiHost, int rmiPort)
  2. throws SchedulerException;
  3. protected void createRemoteScheduler(String schedulerName,
  4. String schedulerInstanceId, String rmiHost, int rmiPort)
  5. throws SchedulerException;

public void createRemoteScheduler(String rmiHost, int rmiPort) throws SchedulerException; protected void createRemoteScheduler(String schedulerName, String schedulerInstanceId, String rmiHost, int rmiPort) throws SchedulerException;

RemoteScheduler 会在第十章,“J2EE 中使用 Quartz”讨论。假如你就是想要一个标准的 Scheduler, 可以调用以下三个版本的方法中的一个:

  1. public void createScheduler(ThreadPool threadPool, JobStore jobStore)
  2. throws SchedulerException;
  3. public void createScheduler(String schedulerName,
  4. String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore)
  5. throws SchedulerException;
  6. public void createScheduler(String schedulerName,
  7. String schedulerInstanceId, ThreadPool threadPool,
  8. JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort,
  9. long idleWaitTime, long dbFailureRetryInterval)
  10. throws SchedulerException;

public void createScheduler(ThreadPool threadPool, JobStore jobStore) throws SchedulerException; public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore) throws SchedulerException; public void createScheduler(String schedulerName, String schedulerInstanceId, ThreadPool threadPool, JobStore jobStore, String rmiRegistryHost, int rmiRegistryPort, long idleWaitTime, long dbFailureRetryInterval) throws SchedulerException;

在上一章上,我们用了一个属性文件来初始化 Scheduler。要通过 DirectSchedulerFactory 创建一个 Scheduler 实例,你必须传递配置参数给其中的一个 createXXX() 方法。在下一节中,我们讨论 StdSchedulerFactory,一个 SchedulerFactory 版本,它依赖于一系列的属性来配置 Scheduler,而不是通过 createXXX() 方法参数来传递配置参数。这样也避免了在代码中对 Scheduler 的配置选项的硬编码。

·使用 StdSchedulerFactory

与 DirectSchedulerFactory 形成鲜明对比的是,org.quartz.impl.StdSchedulerFactory 依赖于一系列的属性来决定如何生产出 Scheduler 实例。你可以通过以下三种途径向工厂提供那些属性:

·通过 java.util.Properties 实例提供
    ·通过外部属性文件提供
    ·通过含用属性文件内容的 java.io.InputStream 实例提供

Java 属性文件
我们这里使用述语“属性文件”,对于 Java 传统来说就是:在一个外部文件中指定一系列的 key=value  对,并且每个 key=value 对独占一行。

代码 4.2 演示了第一种途径,通过一个 java.util.Properties 实例来提供属性。

代码 4.2. 使用 java.util.Properties 实例创建 StdSchedulerFactory

  1. public class Listing_4_2 {
  2. static Log logger = LogFactory.getLog(Listing_4_2.class);
  3. public static void main(String[] args) {
  4. Listing_4_2 example = new Listing_4_2();
  5. example.startScheduler();
  6. }
  7. public void startScheduler() {
  8. // Create an instance of the factory
  9. StdSchedulerFactory factory = new StdSchedulerFactory();
  10. // Create the properties to configure the factory
  11. Properties props = new Properties();
  12. // required to supply threadpool class and num of threads
  13. props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,
  14. "org.quartz.simpl.SimpleThreadPool");
  15. props.put("org.quartz.threadPool.threadCount", "10");
  16. try {
  17. // Initialize the factory with properties
  18. factory.initialize(props);
  19. Scheduler scheduler = factory.getScheduler();
  20. logger.info("Scheduler starting up...");
  21. scheduler.start();
  22. } catch (SchedulerException ex) {
  23. logger.error(ex);
  24. }
  25. }
  26. }

public class Listing_4_2 { static Log logger = LogFactory.getLog(Listing_4_2.class); public static void main(String[] args) { Listing_4_2 example = new Listing_4_2(); example.startScheduler(); } public void startScheduler() { // Create an instance of the factory StdSchedulerFactory factory = new StdSchedulerFactory(); // Create the properties to configure the factory Properties props = new Properties(); // required to supply threadpool class and num of threads props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS, "org.quartz.simpl.SimpleThreadPool"); props.put("org.quartz.threadPool.threadCount", "10"); try { // Initialize the factory with properties factory.initialize(props); Scheduler scheduler = factory.getScheduler(); logger.info("Scheduler starting up..."); scheduler.start(); } catch (SchedulerException ex) { logger.error(ex); } } }
代码 4.2 提供了一个使用 StdSchedulerFactory 创建 Scheduler 实例的很简单的例子。在这个例子中向工厂传递了两个属性,它们分别是实现了 org.quartz.spi.ThreadPool 接口的类名和 Scheduler 用来处理 Job 的线程的数量。这两个属性是必须的,因为它们并没有被指定默认值(我们很快在后面讨论它们)
在代码 4.1 中的 DirectSchedulerFactory,我们调用它其中一个 createXXX() 方法来初始化工厂。而对于 StdSchedulerFactory, 你使用的是一个有效的 initialize() 方法。在工厂初始化之后,你就可以调用它的 getScheduler() 方法获取到 Scheduler 的实例。使用 java.util.Properties 对象传递属性给工厂是一种配置 SchedulerFactory 的方式之一。硬编码配置属性的做法基本不推荐,也是可能的时候应尽力避免的做法。假如你需要修改上一例子中的线程数量,你将不得不修改代码然后重新编译。

幸运的是,StdSchedulerFactory 还有其他的方式来提供必须的属性。工厂也能通过传入一个外部文件名而被初始化,在这个外部文件中包含了这些配置项。应使用 initialize() 的替代方法形式如下:

  1. public void initialize(String filename) throws SchedulerException;

public void initialize(String filename) throws SchedulerException;

要使文件和属性能被成功加载的话,这个文件必须对于 classloader 是可见的。也就是说它必须在你的应用程序的 classpath 中。假如你用的是 java.io.InputStream 去加载文件,你可以使用另一个 initialize() 的替代方法如下:

  1. public void initialize(InputStream propertiesStream) throws SchedulerException;

public void initialize(InputStream propertiesStream) throws SchedulerException;
在第三章,“Hello, Quartz” 你已看到为 SchedulerFactory 从一个叫做 quartz.properties 的外部文件中加载设置的例子。这个外部属性文件就是要用前面的方法来加载。假如你没有为 initialize() 方法指定从哪儿读取属性,那么 StdSchedulerFactory 会试图从名为 quartz.properties 的文件中加载它们。这就是你在第三章看到的行为。

·使用默认的 quartz.properties 文件创建 Scheduler

假如你使用无参的 initialize() 方法,StdSchedulerFactory 会执行以下几个步骤去尝试为工厂加载属性:

1.  检查 System.getProperty("org.quartz.properties") 中是否设置了别的文件名
2.  否则,使用 quartz.properties 作为要加载的文件名
3.  试图从当前工作目录中加载这个文件
4.  试图从系统 classpath 下加载这个文件

在 Quartz Jar 包中的默认 quartz.properties 文件
上面第4步总是能成功的,因为在 Quartz Jar 包中有一个默认的 quartz.properties 文件。假如你想使用另一个替代文件,你必须自己创建一个并确保它在 classpath 上。

使用 StdSchedulerFactory 来创建 Scheduler 实例的方式很普遍,因此在 StdSchedulerFactory 直接提供了一个方便的静态方法 getDefaultScheduler(),它就是使用前面列出的几个步骤来初始化工厂的。这如代码 4.3 所示。

代码 4.3. 使用静态的 getDefaultScheduler() 方法创建 Scheduler

  1. public class Listing_4_3 {
  2. static Log logger = LogFactory.getLog(Listing_4_3.class);
  3. public static void main(String[] args) {
  4. Listing_4_3 example = new Listing_4_3();
  5. example.startScheduler();
  6. }
  7. public void startScheduler() {
  8. try {
  9. // Create a default instance of the Scheduler
  10. Scheduler scheduler =
  11. StdSchedulerFactory.getDefaultScheduler();
  12. logger.info("Scheduler starting up...");
  13. scheduler.start();
  14. } catch (SchedulerException ex) {
  15. logger.error(ex);
  16. }
  17. }}

public class Listing_4_3 { static Log logger = LogFactory.getLog(Listing_4_3.class); public static void main(String[] args) { Listing_4_3 example = new Listing_4_3(); example.startScheduler(); } public void startScheduler() { try { // Create a default instance of the Scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); logger.info("Scheduler starting up..."); scheduler.start(); } catch (SchedulerException ex) { logger.error(ex); } }}

在静态方法 getDefaultScheduler() 方法中调用了空的构造方法。假如之前未调用过任何一个 initialize() 方法,那么无参的 initialize() 方法会被调用。这会开始去按照前面说的顺序加载文件。默认情况下,quartz.properties 会被定位到,并从中加载属性。

·Scheduler 的功能

本章到此为止大部分笔墨都在着重论述如何获得一个 Scheduler 的实例。那么一旦你拿到 Scheduler 的实例之后,你能能此做些什么呢?好,现在开始,上面的例子中告诉了你可以调用它的 start() 方法。Scheduler 的 API 大概包括了 65 个不同的方法。我们不在此全部枚举出来,但是你需要理解其中的一小部分 API。

Scheduler 的 API 可以分组成以下三个类别:

·管理 Scheduler
    ·管理 Job
    ·管理 Trigger 和 Calendar

部署 Job (第一部分)相关推荐

  1. esb 和mq_使用保险丝结构管理MQ和ESB的大型部署,第一部分

    esb 和mq FuseSource最近发布了ActiveMQ和ServiceMix发行版的企业版. 其中的一些主要功能包括增量修补 , 自定义平台安装程序和第三方验证 . 新企业版附带的最酷的功能之 ...

  2. K8S集群应用市场安装部署:第一篇

    这里是引用 操作系统要求 服务器配置信息 基础环境部署 3.1. NTP时钟源同步 3.2. 关闭firewalld服务 3.3. 关闭SElinux服务 3.4. 系统调优配置 3.5. 开启IP转 ...

  3. centos7 redis5.0以前版本 集群部署示例 - 第一篇

    简言 1. redis5.0版本以前的集群部署是使用ruby脚本完成的,ruby脚本的安装少略麻烦(主要原因是系统自动安装的版本太低,无法部署集群,必须手动安装) 2. redis5.0版本以后的集群 ...

  4. 01 Sekiro服务器部署和第一个示例部署成功,js逆向和加解密

    只狼 做穿透部署过程,用于js/android加解密等 第一步: 访问git  : https://github.com/virjar/sekiro 第二步:访问:demoServer编译和部署 · ...

  5. 《跟旺旺老师学Java》_第一章Java简介与JDK部署_第一部分Java是什么

    第一章:Java简介与JDK部署 第一部分:java是什么 "是白云,是瀑布,是海滩,不---,都不是,这是太原大理石二厂生产的景云牌大理石"看到这个标题,脑海中莫名的闪过这句小时 ...

  6. 适合企业使用的服务器虚拟机EXSI ,ERP,OA等服务器部署。第一节:以一个应用者角度介绍并使用EXSI

    适合企业使用的服务器虚拟机EXSI6.7 exsi7 ,ERP,OA等服务器部署 小白服务器部署目录 适合企业使用的服务器虚拟机EXSI6.7 exsi7 ,ERP,OA等服务器部署 前言 一.EXS ...

  7. linux故障转移集群,部署AlwaysOn第一步:搭建Windows服务器故障转移集群

    在Windows Server 2012 R2 DataCenter 环境中搭建集群之前,首先要对Windows服务器故障转移集群(Windows Server Failover Cluster,简称 ...

  8. GitHub实战系列~1.环境部署+创建第一个文件 2015-12-9

    GitHub实战系列汇总:http://www.cnblogs.com/dunitian/p/5038719.html ---------------------------------------- ...

  9. Flink分布式standalone部署方式(第一种方式)

    提前准备 java 版本 1.8.0_101 flink 版本 flink-1.8.2-bin-scala_2.11.tgz hadoop 版本 hadoop-2.8.5.tar.gz flink-h ...

最新文章

  1. Linux多任务编程之五:exit()和_exit()函数(转)
  2. 它是谁?一个比 c3p0 快200倍的数据库连接池!
  3. android singleTop 不起作用
  4. 关于SharePoint中管理列表项权限
  5. JavaFX 2:创建登录表单
  6. 微软发布Enterprise Library 4.1和Unity 1.2
  7. 澜起科技云计算服务器_服务器严重缺货!云应用大爆发!云计算正强势起爆(附龙头)...
  8. lisp正负调换_lisp中如何把符号转换为字符串
  9. Javascript高级程序设计第二版第十一章--DOM2,DOM3--笔记
  10. mysql 支持gbk_MySQL不支持GBK编码的解决方法
  11. aspose word 转pdf中文乱码_pdf转word——都是乱码!怎么办
  12. Unity3D中的线性插值Lerp()函数解析
  13. 绿色版飞信2008 启动时报错“无法注册类别...”的解决办法
  14. 海马玩安卓模拟器linux,Droid4X 0.8.4 海马玩安卓模拟器 安卓的福音
  15. H.264 AVCC header
  16. 安装pycrypto
  17. Python资源(转)
  18. QQ群无故消失或QQ群无故被解散
  19. element-ui中点击菜单,改变当前菜单背景颜色
  20. 神经网络学习的步骤(不是教你怎么学神经网络)

热门文章

  1. java怎么系统输入数字_java怎么输入数字,这些经验不可多得
  2. matlab连通区边界_Matlab图像处理学习笔记(一):二值化、开操作、连通区域提取、重心、ROI...
  3. OpenShift 4 - 向OpenShift内部Image Registry推送Image
  4. 介绍Jupyter和Pandas
  5. 使用Swagger,ApiExplorer和NSwag掌握ASP.NET Core和ABP中的外部Web API
  6. ILSpy 6.0 Preview 1 发布,.NET 反编译工具
  7. C#:生成哈希字符串
  8. python程序gpu运行时间表_python gpu任务及时调度
  9. 简易 Vue 构建--终
  10. java优化上传速度慢怎么办_网站建设中影响网站优化的一些因素