a、Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs。
b、主页:http://www.quartz-scheduler.org/
c、目前最近版本:Quartz 1.8.0 Released - 04/22/2010
2、笔记记录:
JobExecutionContext
当 Scheduler 调用一个 Job,一个 JobexecutionContext 传递给 execute() 方法。
JobExecutionContext 对象让 Job 能访问 Quartz 运行时候环境和 Job 本身的明细数据。
Scheduler生命周期中的方法
scheduler.start(); 开始
scheduler.shutdonw(); 结束
注意:别在 shutdown() 之后调用 start()
Scheduler 实例被关闭之后你就不能调用它的 start() 方法了。这是因为 shutdown() 方法销毁了为
Scheduler 创建的所有的资源(线程,数据库连接等)。假如你在 shutdown() 之后调用 start()你将
收到 SchedulerException 的异常。
org.quartz.Job 接口
把 Quartz 作用到 Java 类上唯一要做的就是让它实现 org.quartz.Job 接口。你的 Job 类可以实现
任何其他想要的接口或继承任何需要的基类,但是它自己或是它的超类必须实现这个 Job 接口。这个
Job 接口只定义了单个方法:
public void execute(JobExecutionContext context)
throws JobExecutionException;
JobDetail
对于部署在 Scheduler 上的每一个 Job 只创建了一个 JobDetail 实例。JobDetail 是作为 Job 实
例进行定义的
JobDataMap
org.quartz.JobDataMap 来定义 Job 的状态。JobDataMap 通过它的超类 org.quartz.util.DirtyFlagMap
实现了 java.util.Map 接口,你可以向 JobDataMap 中存入键/值对,那些数据对可在你的
Job 类中传进行访问。这是一个向你的 Job 传送配置的信息便捷方法。
// Every job has its own job detail
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
以下是例子:
a、构建一个简单的 Quartz 程序
My_Job.java
package org.hyz.quartz;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
public class My_Job implements Job{//一个普通的job,无状态的job
// public class My_Job implements StatefulJob{ //有状态的job
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// TODO Auto-generated method stub
// Object o=context.getJobDetail().getJobDataMap().get("my1");
// Object o1=context.getTrigger().getJobDataMap().get("my2");//触发器中的map
Object o2=context.getMergedJobDataMap().get("my1");//两者合并,当名字一样时trigger覆盖jobdetail
System.out.println(o2+" "+new Date());
}
}
上面是一个job类,只要实现了job接口就可以成为一个job任务, 重写了 Job 接口中的 execute 方法,当调度程序开始运行后,系统会自动调用 HelloWorld 的 execute 方法,也就相当于 TimerTask类中的 run 方法。
a、无状态的Job:继承 org.quartz.Job,对于每一次Job的执行,都会创建一个新的实例JobDetail,Http协议也是无状态的,每次请求都是新的
有状态的Job:继承 org.quartz.StatefulJob,不是指Job有状态,而是指JobDetail任务描述的状态,所以Job还是新的
使用有状态的 Job(指的是JobDetail的状态)
当你需要在两次 Job 执行间维护状态的话,Quartz 框架为此提供了 org.quartz.StatefulJob 接口。
StatefulJob 接口仅仅是扩展了 Job 接口,未加入新的方法。你只需要通过使用与 Job 接口相同的
execute() 方法简单的实现 StatefulJob 接口即可。假如你有已存在的 Job 类,你所有要做的只是
改变 Job 的接口为 org.quartz.StatefulJob。
改变有状态 Job 的 JobDataMap
你可以在有状态 Job 中简单的通过 map 的 put() 方法来修改 JobDataMap.已存在的任何数据会被新
的数据覆盖掉。你也能对无状态的 Job 这么做,但是因为对于无状态 Job 来说,JobDataMap 不会持
久化,所以数据不会保存下来。对于 Trigger 和 JobExecutionContext 上的 JobDataMap 的数据修改
也是没能保存下来的。
b、getMergedJobDataMap()合并,可以直接取Jdetail或Trigger中设置的map中的值
c、scher.start()方法可以在任何地方调用,你的触发器可以随时增加或删除
d、Quartz 支持同时运行多个 Job,他会根据 quartz.properties 初始化相应的线程
MyQuart.java
package org.hyz.quartz;
import java.text.ParseException;
import java.util.Calendar;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.NthIncludedDayTrigger;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;
public class MyQuart {
public void test1() {
//创建一个任务描述JobDetail
JobDetail jd = new JobDetail("my_job", Scheduler.DEFAULT_GROUP,My_Job.class);
jd.getJobDataMap().put("my1", "ab");
//创建触发器
// Trigger str = TriggerUtils.makeSecondlyTrigger(1,5);
// tr.setName(jd.getFullName()+"-Trigger");
SimpleTrigger str=new SimpleTrigger();//没设置组名,是默认的
str.setRepeatInterval(1000);
str.setRepeatCount(5);//执行次数
str.setName(jd.getFullName()+"-Trigger");//getFullName得到组名.my_job
str.getJobDataMap().put("my2", "cd");//同样触发器也有map
Calendar c = Calendar.getInstance();
str.setStartTime(c.getTime());//开始时间,必须设置
//获得调度器Scheduler接口
Scheduler scher=null;
try {
scher=StdSchedulerFactory.getDefaultScheduler();
// scher.start();//可以放在前面,同样执行
scher.scheduleJob(jd,str);//把任务和触发器添加到Scheduler里面
scher.start();//开始启动
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void test2() {
JobDetail jd = new JobDetail("my_job1", Scheduler.DEFAULT_GROUP,My_Job.class);
jd.getJobDataMap().put("my1", "ab");
//处理年月日的Trigger
NthIncludedDayTrigger ndt=new NthIncludedDayTrigger();
ndt.setName(jd.getName()+"-Trigger");
ndt.setIntervalType(NthIncludedDayTrigger.INTERVAL_TYPE_WEEKLY);//设置类型
ndt.setN(Calendar.MONDAY);//每周一
ndt.setFireAtTime("12:00:00");
Calendar c = Calendar.getInstance();
ndt.setStartTime(c.getTime());//开始时间,必须设置
Scheduler scher=null;
try {
scher=StdSchedulerFactory.getDefaultScheduler();
scher.scheduleJob(jd,ndt);
scher.start();
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void test3() {
JobDetail jd = new JobDetail("my_job3", Scheduler.DEFAULT_GROUP,My_Job.class);
jd.getJobDataMap().put("my1", "ab");
//cron触发器
CronTrigger ctr=null;
try {
ctr = new CronTrigger(jd.getFullName()+"-Trigger", Scheduler.DEFAULT_GROUP, "* * * * * ? *");//注意周和日
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Calendar c = Calendar.getInstance();
ctr.setStartTime(c.getTime());
Scheduler scher=null;
try {
scher=StdSchedulerFactory.getDefaultScheduler();
scher.scheduleJob(jd,ctr);
scher.start();//开始启动
} catch (SchedulerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
MyQuart my=new MyQuart();
// my.test1();
my.test2();
my.test3();
}
}
以上是一些常用的触发器:SimpleTrigger,NthIncludedDayTrigger,CronTrigger;
Trigger不是与Job绑定,而是与JobDetail任务描述绑定.一般触发器没设置组名的话,也是默认的scheduler.DEFAULT_GROUP;
为一个 Job 使用多个 Trigger
单个 JobDetail 能够支持多个 Trigger,但一个 Trigger 只能被指派给一个 Job。