quartz(二)
通过官网案例,我们会有个疑惑,
-
为什么调度器(Scheduler)不直接调度任务(Job),而是由触发器(Trigger)去调度呢?是否可以在调度器直接指定一个规则直接调度job呢?
-
根据官网提供的案例,一共有四个名称指令,为什么会设计的这么麻烦?
首先回答第一个问题,既然任务是由Trigger触发,而不是Scheduler直接调度,那是否可以认为,一个任务可以有多个Trigger触发呢?下面通过代码演示验证我们的猜想.
根据上一篇的demo,我i们稍微改变一下代码,新增了一个Trigger
public class QuartzTest {
public static void main(String[] args) {
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
// 0 1 2 3
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever())
.build();
//0 1
Trigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "group2")
.forJob("job1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.scheduleJob(trigger2);
TimeUnit.SECONDS.sleep(3);
scheduler.shutdown();
} catch (Exception se) {
se.printStackTrace();
}
}
}
trigger2会比trigger多一个forJob(),这么做是因为,我们在调度任务的时候,并不是每次都能拿到job这个对象的,所以增加forJob()指定从而触发这个job.
运行结果:
Hello.execute!!!2022.05.29 11:00:01 DefaultQuartzScheduler_Worker-2
Hello.execute!!!2022.05.29 11:00:01 DefaultQuartzScheduler_Worker-1
Hello.execute!!!2022.05.29 11:00:02 DefaultQuartzScheduler_Worker-3
Hello.execute!!!2022.05.29 11:00:03 DefaultQuartzScheduler_Worker-4
Hello.execute!!!2022.05.29 11:00:04 DefaultQuartzScheduler_Worker-5
Hello.execute!!!2022.05.29 11:00:04 DefaultQuartzScheduler_Worker-6
BUILD SUCCESSFUL in 5s
通过运行结果,我们发现,跑了很标准的6次,那我们怎么确定第一个Trigger跑了4次,第二个Trigger跑了2次呢?
此时我们修改一下HelloJob
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
StringJoiner stringJoiner = new StringJoiner("")
.add("Hello.execute!!!")
.add(DFUtil.format(new Date()))
.add(Thread.currentThread().getName())
.add(context.getTrigger().getKey().getName());
System.out.println(stringJoiner);
}
}
再次执行查看打印结果
Hello.execute!!!2022.05.29 11:05:06DefaultQuartzScheduler_Worker-2trigger2
Hello.execute!!!2022.05.29 11:05:06DefaultQuartzScheduler_Worker-1trigger1
Hello.execute!!!2022.05.29 11:05:07DefaultQuartzScheduler_Worker-3trigger1
Hello.execute!!!2022.05.29 11:05:08DefaultQuartzScheduler_Worker-4trigger1
Hello.execute!!!2022.05.29 11:05:09DefaultQuartzScheduler_Worker-5trigger1
Hello.execute!!!2022.05.29 11:05:09DefaultQuartzScheduler_Worker-6trigger2
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.4.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 5s
此时可以验证两个Trigger执行的次数;
那么此时的模型则变为了
一个Scheduler可以调度多个Trigger
那新的问题产生了,一个Trigger是否可以触发多个Job呢?
根据官方文档描述: Many Triggers can point to the same Job, but a single Trigger can only point to one Job
我们知道,一个Job可以被多个Trigger 触发,但是一个Trigger 只能触发一个Job;
下面解决第二个问题,关于JobDetail和Trigger的name和group;
首先,group是用来标记,方便管理的;name是用来标记的,既然name和group都是用来标记的,那也可以只用name去做标记就好了,看一下源码
public TriggerBuilder<T> withIdentity(String name) {
key = new TriggerKey(name, null);
return this;
}
当我们把name和group设置为null时,
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;
}
public static final String DEFAULT_GROUP = "DEFAULT";
此时我们发现,就算group设置为null,它也会默认传一个DEFAULT,这么做是为了什么呢?
Scheduler调度Trigger时有一个方法:scheduler.pauseJobs();它里面需要传入group组名,如果不传入,那么这一组任务就会暂停
Trigger的name和group明白了之后,我们看一下JobDetail的name和group的作用
我们可以试想这样的一个问题,根据官方文档说明,一个Job可以被多个Trigger触发,那么一个Job可不可以被多个Jobdetail引用呢?
我们再来修改一下代码,让Trigger触发Job,Trigger2触发Job2
public class QuartzTest3 {
public static void main(String[] args) {
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
JobDetail job2 = JobBuilder.newJob(HelloJob.class)
.withIdentity("job2", "group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever())
.build();
Trigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "group2")
.forJob("job2", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.scheduleJob(job2,trigger2);
TimeUnit.SECONDS.sleep(3);
scheduler.shutdown();
} catch (Exception se) {
se.printStackTrace();
}
}
}
运行结果
Hello.execute!!!2022.05.29 11:33:12DefaultQuartzScheduler_Worker-1trigger1
Hello.execute!!!2022.05.29 11:33:12DefaultQuartzScheduler_Worker-2trigger2
Hello.execute!!!2022.05.29 11:33:13DefaultQuartzScheduler_Worker-3trigger1
Hello.execute!!!2022.05.29 11:33:14DefaultQuartzScheduler_Worker-4trigger1
Hello.execute!!!2022.05.29 11:33:15DefaultQuartzScheduler_Worker-5trigger1
Hello.execute!!!2022.05.29 11:33:15DefaultQuartzScheduler_Worker-6trigger2
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.4.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 7s
通过代码结果,我们可以判定,quartz的真实模型如下
综上,我们可以获知:一个Job可以被多个Trigger 触发,但是一个Trigger 只能触发一个Job;一个Job可以被多个JobDetail所关联,不过我们在实际使用过程中,一个Job并不会被多个JobDetail所关联;实际生产中,还是以一个Job可以被多个Trigger 触发,一个JobDaetail只关联一个Job;因为生产过程中,不仅仅是自动触发任务,还需要手动去触发任务;
我们再次修改代码,将四个标记全部注释掉
public class QuartzTest4 {
public static void main(String[] args) {
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail job = JobBuilder.newJob(HelloJob.class)
// .withIdentity("job1", "group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
// .withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)
.repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
TimeUnit.SECONDS.sleep(3);
scheduler.shutdown();
} catch (Exception se) {
se.printStackTrace();
}
}
}
运行结果
Hello.execute!!!2022.05.29 11:43:36DefaultQuartzScheduler_Worker-16da64b5bd2ee-f5a2f797-524c-44ab-802e-3833ccbc6433
Hello.execute!!!2022.05.29 11:43:37DefaultQuartzScheduler_Worker-26da64b5bd2ee-f5a2f797-524c-44ab-802e-3833ccbc6433
Hello.execute!!!2022.05.29 11:43:38DefaultQuartzScheduler_Worker-36da64b5bd2ee-f5a2f797-524c-44ab-802e-3833ccbc6433
Hello.execute!!!2022.05.29 11:43:39DefaultQuartzScheduler_Worker-46da64b5bd2ee-f5a2f797-524c-44ab-802e-3833ccbc6433
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.4.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 8s