前序:
我们已经在前面的内容能里看到了,我们用 Scheduler 来管理我们的 Job;创建并关联触发器以使 Job 能被触发执行;以及如可选择 calendar 为给定的时程安排提供更多的灵活性。
[b]1.Quartz 调度器的介绍 [/b]
调度器(Scheduler) 是Quartz 框架的心脏,Scheduler也是 Quartz 的主要 API。对于 Quartz 用户来说,多数时候与框架的交互是发生于 Scheduler 之上的。客服端与 Scheduler 交互是通过 org.quartz.Scheduler接口的。从Quartz内部来说,我们可以从前面看出,它是任务执行的一个平台,如果光有任务没有调度器的存在,众多任务也不会实现为多任务的批处理;
我们访问Quartz的时候,其实Scheduler并不是真正的处理类,这个Scheduler 的实现,在这种情况下,是一个代理,对其中方法调用会传递到 QuartzScheduler 实例上。QuartzScheduler对于客户端是不可见的,并且也不存在与此实例的直接交互;
QuartzScheduler 处在框架根的位置,它是一个引擎驱动着整个框架。并非所有的功能都直接内建到 QuartzScheduler,然而,框架为灵活性和可配置性考虑而设计,所以许多重要的功能由分离的组件和子框架实现。这就意味着 Quartz 用户可以用自己某个关键特征实现来替换原有默认实现。即使 QuartzScheduler 代理了它的一些职责,但它仍然掌控着整个作业调度流程
[b]2.Quartz Scheduler 的类层次 [/b]
Scheduler为一个接口,客户端会同两种类型的 Scheduler 交互,它们都实现了
org.quartz.Scheduler 接口。
Scheduler
StdScheduler RemoteScheduler;
[b]3.Quartz SchedulerFactory 调度器工厂类[/b]
Quartz SchedulerFactory 为一个创建任务调度器的工厂类;
他的工厂方法来确保了构造出 Sheduler 实例并正确的得到初始化,当 Scheduler 实例被创建之后,就会存到一个仓库中(org.quartz.impl.SchedulerRepository),这个仓库还提供了通过一个 class loader 查询实例的机制。要使用 Scheduler 实例,客户端必须从工厂(和随同的仓库中)使用不同方法调用来获取到它们。换句话说,要通过工厂创建一个 Scheduler 实例并获取到它需要经由两次方法调用。有一些方便的方法封装了那两个方法,你将很快能看到。
一个是create动作,一个是get动作;
SchedulerFactory也只是一个接口,他有具体两个实现类分别为:
[color=red]
a.org.quartz.impl.DirectoSchedulerFactory
b.org.quartz.impl.StdSchedulerFactory
[/color]
[b]4.DirectSchedulerFactory [/b]
DirectSchedulerFactory 是为那些想绝对控制 Scheduler 实例是如何生产出的人所
设计的。下面的代码显示了最简单的方式去使用 DirectSchedulerFactory
来创建一个 Scheduler 实例。
[color=red]注意:
在调用 getScheduler() 方法之前调用其中的一个 createXXX 方法 ;[/color]
方法 createVolatileScheduler() 方法不会返回 scheduler 的实例。createXXX() 方法是告诉工厂如何配置要创建的 Scheduler 实例。你必须调用方法 getScheduler() 获取到在工厂上执行方法 createXXX() 产生的实例。实际上,在调用 getScheduler() 方法之前,你必须调用其中一个 createXXX() 方法;否则,你将有收到一个 SchedulerException 错误,因为根本没有 Scheduler 实例存在。
我们上面获取的为Scheduler接口的实现StdScheduler的实例,那么我们如何根据factory来创建一个RemoteScheduler呢?
对于标准任务调度器的创建,通过工厂类的createVolatileScheduler()方法是不够的
[b]5.StdSchedulerFactory[/b]
我们都可以看出来,上面DirectSechdulerFactory是通过create的方式来初始化任务调度器的相关信息,我们可否通过文件配置的形式来实现我们的
任务调度器信息的初始化呢?StdSchedulerFactory,另一个 SchedulerFactory 版本,它依赖于一系列的属性来配置 Scheduler,而不是通过 createXXX() 方法参数来传递配置参数。这样也避免了在代码中对 Scheduler 的配置选项的硬编码。
它提供了三种方式来实现通知工厂类创建任务调度器实例的属性;
我们可以通过以下三种途径向工厂提供那些属性:
·通过 java.util.Properties 实例提供
·通过外部属性文件提供
·通过含用属性文件内容的 java.io.InputStream 实例提供
下面我们将一个个的来实现上面的三种方式
[b]a.通过java.util.Properties 实例创建 StdSchedulerFactory [/b]
[b]b.外部文件实现属性初始化[/b]
工厂也能通过传入一个外部文件名而被初始化,在这个外部文件中包含了这些配置项。应使用 initialize() 的替代方法形式如下:
Java 属性文件
我们这里使用述语“属性文件”,对于 Java 传统来说就是:在一个外部文件中指定一系列的 key=value 对,并且每个 key=value 对独占一行。
要使文件和属性能被成功加载的话,这个文件必须对于 classloader 是可见的。也就是说它必须在你的应用程序的 classpath 中
[b] c.文件输入流的形式[/b]
假如你用的是 java.io.InputStream 去加载文件,你可以使用另一个 initialize() 的替代方法如下:
注意,假使我们对于stdSechedulerFactory的initialize没有指定属性,那么 StdSchedulerFactory 会试图从名为 quartz.properties 的文件中加载它们;
对于默认读取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 直接提供了一个方便的静态方法 getDefaultScheduler(),它也就是调用了前面的三个initialize方法中的一个;
如果一次initialize方法都没有别调用,则它将调用一个默认的无参initialize方法!也就是说,它将默认将quartz.properties文件做为默认的初始化信息;
[b]任务调度器的作用[/b]
Scheduler 的 API 可以分组成以下三个类别:
·管理 Scheduler
·管理 Job
·管理 Trigger 和 Calendar
我们已经在前面的内容能里看到了,我们用 Scheduler 来管理我们的 Job;创建并关联触发器以使 Job 能被触发执行;以及如可选择 calendar 为给定的时程安排提供更多的灵活性。
[b]1.Quartz 调度器的介绍 [/b]
调度器(Scheduler) 是Quartz 框架的心脏,Scheduler也是 Quartz 的主要 API。对于 Quartz 用户来说,多数时候与框架的交互是发生于 Scheduler 之上的。客服端与 Scheduler 交互是通过 org.quartz.Scheduler接口的。从Quartz内部来说,我们可以从前面看出,它是任务执行的一个平台,如果光有任务没有调度器的存在,众多任务也不会实现为多任务的批处理;
我们访问Quartz的时候,其实Scheduler并不是真正的处理类,这个Scheduler 的实现,在这种情况下,是一个代理,对其中方法调用会传递到 QuartzScheduler 实例上。QuartzScheduler对于客户端是不可见的,并且也不存在与此实例的直接交互;
QuartzScheduler 处在框架根的位置,它是一个引擎驱动着整个框架。并非所有的功能都直接内建到 QuartzScheduler,然而,框架为灵活性和可配置性考虑而设计,所以许多重要的功能由分离的组件和子框架实现。这就意味着 Quartz 用户可以用自己某个关键特征实现来替换原有默认实现。即使 QuartzScheduler 代理了它的一些职责,但它仍然掌控着整个作业调度流程
[b]2.Quartz Scheduler 的类层次 [/b]
Scheduler为一个接口,客户端会同两种类型的 Scheduler 交互,它们都实现了
org.quartz.Scheduler 接口。
Scheduler
StdScheduler RemoteScheduler;
[b]3.Quartz SchedulerFactory 调度器工厂类[/b]
Quartz SchedulerFactory 为一个创建任务调度器的工厂类;
他的工厂方法来确保了构造出 Sheduler 实例并正确的得到初始化,当 Scheduler 实例被创建之后,就会存到一个仓库中(org.quartz.impl.SchedulerRepository),这个仓库还提供了通过一个 class loader 查询实例的机制。要使用 Scheduler 实例,客户端必须从工厂(和随同的仓库中)使用不同方法调用来获取到它们。换句话说,要通过工厂创建一个 Scheduler 实例并获取到它需要经由两次方法调用。有一些方便的方法封装了那两个方法,你将很快能看到。
一个是create动作,一个是get动作;
SchedulerFactory也只是一个接口,他有具体两个实现类分别为:
[color=red]
a.org.quartz.impl.DirectoSchedulerFactory
b.org.quartz.impl.StdSchedulerFactory
[/color]
[b]4.DirectSchedulerFactory [/b]
DirectSchedulerFactory 是为那些想绝对控制 Scheduler 实例是如何生产出的人所
设计的。下面的代码显示了最简单的方式去使用 DirectSchedulerFactory
来创建一个 Scheduler 实例。
/**
* 测试DirectSchedulerFactory的功能
* @author liuwei
*
*/
public class DirectSchedulerFactoryTest {
static Log logger = LogFactory.getLog
(DirectSchedulerFactoryTest.class);
/**
* 测试DirectSchedulerFactory的功能
* @param args
*/
public static void main(String[] args) {
DirectSchedulerFactoryTest example=new DirectSchedulerFactoryTest();
example.startScheduler();
}
/**
*根据DirectSchedulerFactory创建一个任务调度器实例
*/
public void startScheduler() {
/*静态方法 getInstance() 获取到工厂的实例*/
DirectSchedulerFactory factory=DirectSchedulerFactory.getInstance()
try {
/*
* createVolatileScheduler() 方法创建 Scheduler 实例的。
* 方法 createVolatileScheduler() 带有单个参数:要创建的线程数量
*/
factory.createVolatileScheduler(10);
//获取一个任务调度器实例通过工厂类
Scheduler scheduler = factory.getScheduler();
//启动该任务调度器,并执行上面注册的作业任务
logger.info("Scheduler starting up...");
//启动任务调度器;
scheduler.start();
} catch (SchedulerException ex) {
logger.error(ex);
}
}
}
[color=red]注意:
在调用 getScheduler() 方法之前调用其中的一个 createXXX 方法 ;[/color]
方法 createVolatileScheduler() 方法不会返回 scheduler 的实例。createXXX() 方法是告诉工厂如何配置要创建的 Scheduler 实例。你必须调用方法 getScheduler() 获取到在工厂上执行方法 createXXX() 产生的实例。实际上,在调用 getScheduler() 方法之前,你必须调用其中一个 createXXX() 方法;否则,你将有收到一个 SchedulerException 错误,因为根本没有 Scheduler 实例存在。
我们上面获取的为Scheduler接口的实现StdScheduler的实例,那么我们如何根据factory来创建一个RemoteScheduler呢?
public void createRemoteScheduler(String rmiHost, int rmiPort)
throws SchedulerException;
protected void createRemoteScheduler(String schedulerName,
String schedulerInstanceId, String rmiHost, int rmiPort)
throws SchedulerException;
对于标准任务调度器的创建,通过工厂类的createVolatileScheduler()方法是不够的
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;
[b]5.StdSchedulerFactory[/b]
我们都可以看出来,上面DirectSechdulerFactory是通过create的方式来初始化任务调度器的相关信息,我们可否通过文件配置的形式来实现我们的
任务调度器信息的初始化呢?StdSchedulerFactory,另一个 SchedulerFactory 版本,它依赖于一系列的属性来配置 Scheduler,而不是通过 createXXX() 方法参数来传递配置参数。这样也避免了在代码中对 Scheduler 的配置选项的硬编码。
它提供了三种方式来实现通知工厂类创建任务调度器实例的属性;
我们可以通过以下三种途径向工厂提供那些属性:
·通过 java.util.Properties 实例提供
·通过外部属性文件提供
·通过含用属性文件内容的 java.io.InputStream 实例提供
下面我们将一个个的来实现上面的三种方式
[b]a.通过java.util.Properties 实例创建 StdSchedulerFactory [/b]
/**
* 通过java.util.Properties类来实现创建Secheduler
* @author liuwei
*/
public class PropertiesStdSechedulerFactory {
static Log logger = LogFactory.getLog
(PropertiesStdSechedulerFactory.class);
/**
*调度器的执行模拟
*/
public static void main(String[] args) {
PropertiesStdSechedulerFactory example = new
PropertiesStdSechedulerFactory();
example.startScheduler();
}
/**
* 获取任务调度器方法
*/
public void startScheduler() {
/*创建一个StdSchedulerFactory实例*/
StdSchedulerFactory factory = new StdSchedulerFactory();
/*创建一个Properties类,来实现对工厂类的属性初始化*/
Properties props = new Properties();
/*
* 初始化两个属性
* StdSchedulerFactory.PROP_THREAD_POOL_CLASS --
* org.quartz.simpl.SimpleThreadPool
* org.quartz.threadPool.threadCount --10
*/
props.put(StdSchedulerFactory.PROP_THREAD_POOL_CLASS,"org.quartz.simpl.SimpleThreadPool");
props.put("org.quartz.threadPool.threadCount", "10");
try {
/*根据属性信息初始化工厂类*/
factory.initialize(props);
//获取一个任务调度器实例通过工厂类
Scheduler scheduler = factory.getScheduler();
//启动该任务调度器,并执行上面注册的作业任务
logger.info("Scheduler starting up...");
scheduler.start();
} catch (SchedulerException ex) {
logger.error(ex);
}
}
}
[b]b.外部文件实现属性初始化[/b]
工厂也能通过传入一个外部文件名而被初始化,在这个外部文件中包含了这些配置项。应使用 initialize() 的替代方法形式如下:
public void initialize(String filename) throws SchedulerException;
Java 属性文件
我们这里使用述语“属性文件”,对于 Java 传统来说就是:在一个外部文件中指定一系列的 key=value 对,并且每个 key=value 对独占一行。
要使文件和属性能被成功加载的话,这个文件必须对于 classloader 是可见的。也就是说它必须在你的应用程序的 classpath 中
[b] c.文件输入流的形式[/b]
假如你用的是 java.io.InputStream 去加载文件,你可以使用另一个 initialize() 的替代方法如下:
public void initialize(InputStream propertiesStream) throws SchedulerException;
注意,假使我们对于stdSechedulerFactory的initialize没有指定属性,那么 StdSchedulerFactory 会试图从名为 quartz.properties 的文件中加载它们;
对于默认读取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 直接提供了一个方便的静态方法 getDefaultScheduler(),它也就是调用了前面的三个initialize方法中的一个;
如果一次initialize方法都没有别调用,则它将调用一个默认的无参initialize方法!也就是说,它将默认将quartz.properties文件做为默认的初始化信息;
[b]任务调度器的作用[/b]
Scheduler 的 API 可以分组成以下三个类别:
·管理 Scheduler
·管理 Job
·管理 Trigger 和 Calendar