Quartz是一个开源的任务调度框架,它有别于Timer,有比Timer更好的性能。由于故障切换以及负载均衡能力使得Quartz框架具有如下特点:
1.强大的调度功能。
2.灵活的应用方式。
3.分布式和集群能力。
以上三个特点使得Quartz在多任务调度以及分布式中具有很大的作用,以下通过Quart框架中几个重要的组件来了解Quartz框架是如何工作的。关于Quartz框架,我们需要了解的几个组件的概念是:Job组件系列、Trigger组件系列以及Scheduler系列。本文主要讲述的是Job组件系列。
首先Job是一个接口,如下代码所示,该接口只有一个方法,因此Job实现类只需要实现execute方法即可。
public interface Job {
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Interface.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* <p>
* Called by the <code>{@link Scheduler}</code> when a <code>{@link Trigger}</code>
* fires that is associated with the <code>Job</code>.
* </p>
*
* <p>
* The implementation may wish to set a
* {@link JobExecutionContext#setResult(Object) result} object on the
* {@link JobExecutionContext} before this method exits. The result itself
* is meaningless to Quartz, but may be informative to
* <code>{@link JobListener}s</code> or
* <code>{@link TriggerListener}s</code> that are watching the job's
* execution.
* </p>
*
* @throws JobExecutionException
* if there is an exception while executing the job.
*/
void execute(JobExecutionContext context)
throws JobExecutionException;
}
创建Job实现类之后,需要将Job实例绑定到JobDetail对象中,其中JobDetail中是一个接口,并继承了Serializable和Cloneable接口。
public interface JobDetail extends Serializable, Cloneable
创建JobDetail实例需要调用JobBuilder类中的静态方法newJob方法,该方法封装了创建JobBuilder对象的过程。
public static JobBuilder newJob() {
return new JobBuilder();
}
/**
* Create a JobBuilder with which to define a <code>JobDetail</code>,
* and set the class name of the <code>Job</code> to be executed.
*
* @return a new JobBuilder
*/
public static JobBuilder newJob(Class <? extends Job> jobClass) {
JobBuilder b = new JobBuilder();
b.ofType(jobClass);
return b;
}
创建JobBuilder对象之后需要绑定Job实现类,通过调用实例方法withIdentity方法来进行绑定的,其中参数group可以缺省。可以看到该方法中通过创建一个JobKey对象,并返回JobBuilder对象,从而实现绑定的。
public JobBuilder withIdentity(String name) {
key = new JobKey(name, null);
return this;
}
/**
* Use a <code>JobKey</code> with the given name and group to
* identify the JobDetail.
*
* <p>If none of the 'withIdentity' methods are set on the JobBuilder,
* then a random, unique JobKey will be generated.</p>
*
* @param name the name element for the Job's JobKey
* @param group the group element for the Job's JobKey
* @return the updated JobBuilder
* @see JobKey
* @see JobDetail#getKey()
*/
public JobBuilder withIdentity(String name, String group) {
key = new JobKey(name, group);
return this;
}
/**
* Use a <code>JobKey</code> to identify the JobDetail.
*
* <p>If none of the 'withIdentity' methods are set on the JobBuilder,
* then a random, unique JobKey will be generated.</p>
*
* @param jobKey the Job's JobKey
* @return the updated JobBuilder
* @see JobKey
* @see JobDetail#getKey()
*/
public JobBuilder withIdentity(JobKey jobKey) {
this.key = jobKey;
return this;
}
再来看看JobKey的源码,它继承了Key<T>一个泛型类,并且有两个构造函数:
public JobKey(String name) {
super(name, null);
}
public JobKey(String name, String group) {
super(name, group);
}
可以看出这两个构造函数都继承了父类构造函数,接下来看看Key的源码,这也解释了前面withIdentity方法的group参数为何可以缺省,因为它一旦缺省就会默认为DEFAULT_GROUP。
public Key(String name, String group) {
if(name == null)
throw new IllegalArgumentException("Name cannot be null.");
this.name = name;
if(group != null)
this.group = group;
else
this.group = DEFAULT_GROUP;
}
最后回到JobBuilder创建JobDetail对象的最核心的方法build方法:
public JobDetail build() {
JobDetailImpl job = new JobDetailImpl();
job.setJobClass(jobClass);
job.setDescription(description);
if(key == null)
key = new JobKey(Key.createUniqueName(null), null);
job.setKey(key);
job.setDurability(durability);
job.setRequestsRecovery(shouldRecover);
if(!jobDataMap.isEmpty())
job.setJobDataMap(jobDataMap);
return job;
}
从上面build方法可以看出,内部创建了一个JobDetail实现类对象,并且将一些相关的信息保存到该对象中并返回。从而实现JobDetail的创建。
从上面整个过程来说,首先实现Job接口创建实现类。然后需要创建JobDetail对象,该对象的创建比较复杂,首先调用JobBuilder类的类方法newJob创建对象,并且调用实例方法withIdentity方法该方法是通过内部创建一个JobKey实例,将Job实现类的实例对象绑定其中,最后调用build方法则是为了创建JobDetail实现类的对象,并为对象初始化一些信息。
以上就是Job组件系列的关系以及工作流程。