继续讨论job和jobDetail的知识。
1、能不能将同一个jobDetail或者是Trigger重复添加到同一个scheduler中,这个问题是我在学习quartz时突发奇想思考到的。所有的jobDetail和Trigger都被存储起来了,quartz中含有一个接口:JobStore,他的javadoc这么写:存储Job和Trigger供QuartzScheduler调用。我debug发现使用的实现类是RAMJobStore,它里面的storeJob(JobDetail, boolean)方法中定义了对添加JobDetail的描述:如果boolean变量是true,则会覆盖原先已经有的jobDetail,如果是false则会抛异常,jobDetail重复的标准是JobKey的相同,也就是调用equals的结果相同。在源码中是将存储的jobdetail按照jobKey和group进行了分组,存储到hashMap中。
2、一个scheduler中只能添加一个jobDetail吗,或者是能不能在一个scheduler中通过添加多个trigger但是只添加一个JobDetail?在我看来是否定的,最起码在使用RamJobStore时是这样,而这个store是官网推荐的store。在这个类中添加JobDetail时,会调用这个方法:
public void storeJobAndTrigger(JobDetail newJob,
OperableTrigger newTrigger) throws JobPersistenceException {
storeJob(newJob, false);
storeTrigger(newTrigger, false);
}
public void storeJob(JobDetail newJob,boolean replaceExisting) throws ObjectAlreadyExistsException {
JobWrapper jw = new JobWrapper((JobDetail)newJob.clone());
boolean repl = false;
synchronized (lock) {
if (jobsByKey.get(jw.key) != null) {//我加的注释,如果已经有这个jobKey,并且replaceExisting为false,就比报错,而且上面调用传入的就是false。
//也就是不支持多个相同的jobdetail
if (!replaceExisting) {
throw new ObjectAlreadyExistsException(newJob);
}
repl = true;
}
if (!repl) {
// get job group
HashMap<JobKey, JobWrapper> grpMap = jobsByGroup.get(newJob.getKey().getGroup());
if (grpMap == null) {
grpMap = new HashMap<JobKey, JobWrapper>(100);
jobsByGroup.put(newJob.getKey().getGroup(), grpMap);
}
// add to jobs by group
grpMap.put(newJob.getKey(), jw);
// add to jobs by FQN map
jobsByKey.put(jw.key, jw);
} else {
// update job detail
JobWrapper orig = jobsByKey.get(jw.key);
orig.jobDetail = jw.jobDetail; // already cloned
}
}
}
3、Trigger是如何知道要调用哪个JobDetail呢? Trigger里面含有JobKey,通过这个在RamJobStore中的按照JobKey分组的hashMap中查找的。
4、能不能改变已经提交到Scheduler的jobDetail,是可以的。Scheduler中提供了接口:Scheduler.deleteJob(new JobKey("myJob", Scheduler.DEFAULT_GROUP));这样就可以把已经提交的jobDetail还有跟他一起提交的所有Trigger都删除(一个JobDetail可以有多个Trigger),源码中是在RamJobStore中的removeJob方法中提及的。
5、文档中还提及了再jobDetail已经不会再被调度的情况下,Scheduler对jobDetail的处理,默认是将其删除,也就是如果一个JobDetail已经不会再被调度,那么就会从scheduler中将其删除。我们可以做个实验:
package demo;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.StdSchedulerFactory;
import job.HelloJob;
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
try {
StdSchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
StdScheduler sched = (StdScheduler) schedFact.getScheduler();
//开始调度器
sched.start();
//创建job任务
JobDetail job = newJob(HelloJob.class).withIdentity("myJob", Scheduler.DEFAULT_GROUP).build();
//创建trigger,触发器
Trigger trigger = newTrigger().withIdentity("myTrigger",Scheduler.DEFAULT_GROUP).startNow()
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(2,3)).build();//每隔三秒执行一次,一共执行2次
//将任务和触发器绑定到调度器
sched.scheduleJob(job, trigger);
JobDetail j1 = sched.getJobDetail(new JobKey("myJob", Scheduler.DEFAULT_GROUP));
System.out.println("之前:" + (j1 == null));
Thread.sleep(10000);//休息10秒,等待调度执行完成,调度一共只有不到4秒的时间就会完成,因为第一次马上就执行。
j1 = sched.getJobDetail(new JobKey("myJob", Scheduler.DEFAULT_GROUP));
System.out.println("之后:" +(j1 == null));
Thread.sleep(1000000);
sched.shutdown();
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
在HelloJob中的execute方法中只是输出一句话 xxxx.
实验结果如下:
之前:false
xxxx
xxxx
之后:true
结果证明会将其删除,文档中提及可以将这个jobDetail注册为持久化的,通过将这个代码改为如下:
//创建job任务
JobDetail job = newJob(HelloJob.class).withIdentity("myJob", Scheduler.DEFAULT_GROUP).storeDurably(true).build();
添加了storeDurable(true),这样再运行代码,就会发现,都是false了。
之前:false
xxxx
xxxx
之后:false
6、文档中还提及了requestRecovery的概念,但是我没有看懂,如果有人看懂了,可以给我留言,或者是加我qq:1902442871。