Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。
quartz核心概念
Job:是一个接口,表示一个工作,要执行的具体内容。只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中;
JobDetail:JobDetail表示一个具体的可执行的调度程序,Job是这个可执行程调度程序所要执行的内容,另外JobDetail还包含了这个任务调度的方案和策略。Quartz在每次执行Job时,都重新创建一个Job实例,所以它不直接接受一个Job的实例,相反它接收一个Job实现类,以便运行时通过newInstance()的反射机制实例化Job。因此需要通过一个类来描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息,JobDetail承担了这一角色。
Trigger:是一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或者以固定时间间隔周期执行,SimpleTrigger是最适合的选择;而CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;
Calendar:org.quartz.Calendar和java.util.Calendar不同,它是一些日历特定时间点的集合(可以简单地将org.quartz.Calendar看作java.util.Calendar的集合——java.util.Calendar代表一个日历时间点,无特殊说明后面的Calendar即指org.quartz.Calendar)。一个Trigger可以和多个Calendar关联,以便排除或包含某些时间点。假设,我们安排每周星期一早上10:00执行任务,但是如果碰到法定的节日,任务则不执行,这时就需要在Trigger触发机制的基础上使用Calendar进行定点排除。
Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。
ThreadPool:Scheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提高运行效率。
Quartz的工作原理:
1、scheduler是一个计划调度器容器(总部),容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就班自动去执行。
2、JobDetail是一个可执行的工作,它本身可能是有状态的。
3、Trigger代表一个调度参数的配置,什么时候去调。
4、当JobDetail和Trigger在scheduler容器上注册后,形成了装配好的作业(JobDetail和Trigger所组成的一对儿),就可以伴随容器启动而调度执行了。
5、scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
总结起来就是,Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例。
Quartz的两大触发器
Quartz有两大触发器,SimpleTrigger和CronTrigger。当且仅需触发一次或者以固定时间间隔周期触发执行时使用SimpleTrigger触发器,需要定时调度任务时使用CronTrigger。
SimpleTrigger:当需要在规定的时间执行一次或在规定的时间段以一定的时间间隔重复触发执行Job时,SimpleTrigger就可以满足要求;SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔,重复次数属性的值可以为0、正整数、或常量 SimpleTrigger.REPEAT_INDEFINITELY,重复的时间间隔属性值必须为0或长整型的正整数,以毫秒作为时间单位,当重复的时 间间隔为0时,意味着与Trigger同时触发执行(或几乎与Scheduler开始时同时触发执行)。如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每间隔10秒钟触发一次直到指定的结束时间的 Trigger,而无需去计算从开始到结束的所重复的次数,我们只需简单的指定结束时间和使用REPEAT_INDEFINITELY作为重复次数的属性 值即可(我们也可以指定一个比在指定结束时间到达时实际执行次数大的重复次数)。
CronTrigger:支持比 SimpleTrigger 更具体的调度,而且也不是很复杂。基于 cron 表达式,CronTrigger 支持类似日历的重复间隔,而不是单一的时间间隔。Cron表达式Cron Expression参看本人以下博客:http://blog.csdn.net/lmb55/article/details/51013044
两种调度方式的简单使用:
TestQuartzJob.java
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
/**
* 一个简单的任务,say hello word
*/
public class TestQuartzJob implements Job {
public TestQuartzJob() {
}
public void execute(JobExecutionContext context)throws JobExecutionException {
System.out.println("Hello World! - " + new Date());
}
}
TestQuartzScheduling.java
import java.util.Date;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
import org.simpleproxy.Quartz.TestQuartzJob;
public class TestQuartzScheduling {
/**
* 使用SimpleTrigger间隔调度任务
* @throws Exception
*/
public void simpleRun() throws Exception {
//1、创建JobDetial对象
JobDetail jobDetail = new JobDetail();
//设置工作项
jobDetail.setJobClass(TestQuartzJob.class);
jobDetail.setName("MyJob_1");
jobDetail.setGroup("JobGroup_1");
// JobDetail jobDetail = new JobDetail("MyJob_1","JobGroup_1",TestQuartzJob.class);
//2、创建Trigger对象 SimpleTrigger
SimpleTrigger strigger = new SimpleTrigger();
strigger.setName("Trigger_1");
strigger.setGroup("Trigger_Group_1");
strigger.setStartTime(new Date());
//设置重复停止时间,并销毁该Trigger对象
java.util.Calendar c = java.util.Calendar.getInstance();
c.setTimeInMillis(System.currentTimeMillis() + 1000 * 1L);
strigger.setEndTime(c.getTime());
strigger.setFireInstanceId("Trigger_1_id_001");
//设置重复间隔时间
// strigger.setRepeatInterval(100 * 1L);
// strigger.setRepeatInterval(500 * 1L);
strigger.setRepeatInterval(1000 * 1L);
//设置重复执行次数
strigger.setRepeatCount(3);
//3、创建Scheduler对象,并配置JobDetail和Trigger对象
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = null;
try {
scheduler = sf.getScheduler();
scheduler.scheduleJob(jobDetail, strigger);
//4、并执行启动、关闭等操作
scheduler.start();
// scheduler.shutdown(true); //关闭调度器
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 使用CronTrigger定时调度任务
* @throws Exception
* @author Administrator
* @date 2017-9-6
*/
public void cronRun() throws Exception {
//创建Scheduler对象,并配置JobDetail和Trigger对象
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//创建JobDetial对象
JobDetail jobDetail = new JobDetail("testQuartzJob",Scheduler.DEFAULT_GROUP, TestQuartzJob.class);
String cronExpression = "30/5 * * * * ?"; // 每分钟的30s起,每5s触发任务
//创建Trigger对象CronTrigger
CronTrigger cronTrigger = new CronTrigger("cronTrigger",Scheduler.DEFAULT_GROUP, cronExpression);
scheduler.scheduleJob(jobDetail, cronTrigger);
scheduler.start();
}
public static void main(String[] args) throws Exception {
TestQuartzScheduling example = new TestQuartzScheduling();
example.simpleRun();
example.cronRun();
}
}
运行结果:
在使用SimpleTrigger间隔调度任务的时候,我设置了几个不同的重复间隔时间,运行得到了不同的结果。
注意:本文示例使用的Quartz版本是1.8.6。
稍后本人会根据源码,来学习一下Quartz的原理,有兴趣的同学,可以先参看下面的几篇分析文章:
Quartz原理解析:
http://blog.csdn.net/guolong1983811/article/details/51501346
http://lavasoft.blog.51cto.com/62575/181907/