文章目录
Quartz 三要素
quartz [kwɔːts] 石英
调度器(Scheduler)
:所有的任务都是从这里开始。
触发器(Trigger)
:定义任务执行的方式、间隔。
任务(JobDetail & Job
) :定义任务具体执行的逻辑。
Scheduler
scheduler 是quartz的核心所在,所有的任务都是通过scheduler开始。
scheduler是一个接口类,所有的具体实现类都是通过SchedulerFactory工厂类实现,但是SchedulerFactory有两个具体的实现类,如图:
1.StdSchedulerFactory
:默认值加载是当前工作目录下的”quartz.properties”属性文件
。如果加载失败,会去加载org/quartz包下的”quartz.properties”属性文件。一般使用这个实现类就能满足我们的要求。
2.DirectSchedulerFactory:这个我也没用过QAQ,听说是为那些想绝对控制 Scheduler 实例是如何生产出的人所设计的。
Trigger
惊奇的发现trigger采用的也是buidler模式-。-(想了解什么事builder模式可以看下我的另外一篇博客https://blog.csdn.net/bicheng4769/article/details/80988996)
这里我只给大家介绍一些常用的方法,其余的可以自己查看文档:
withIdentity() 给触发器一些属性 比如名字,组名。
startNow() 立刻启动
withSchedule(ScheduleBuilder schedBuilder) 以某种触发器触发。
usingJobData(String dataKey, Boolean value) 给具体job传递参数。
Trigger的重点内容就是在withSchedule这个方法,从参数开始:查看SchedulerBuilder,这个是个抽象类,一共有4种具体实现方法,如图:
SimpleScheduleBuilder
最简单的触发器,表示从某一时刻开始,以一定的时间间隔执行任务。
属性:
repeatInterval 重复间隔。
repeatCount 重复次数。
比如:现在开始,以后每一个小时执行一次。
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInHours(1)
.repeatForever()).build();
CronScheduleBuilder
cron表达式。
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
//加入 scheduler之后立刻执行
.startNow()
//定时 ,每个1秒钟执行一次
.withSchedule(cronSchedule("0 0/2 8-17 * * ?") // 每天8:00-17:00,每隔2分钟执行一次
).build();
JobDetail & Job
jobdetail 就是对job的定义,而job是具体执行的逻辑内容。
具体的执行的逻辑需要实现 job类,并实现execute方法。
为什么设计成JobDetail + Job,不直接使用Job?
JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。
这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,Sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。
如何禁止并发执行?
项目中出现了一种情况,本来job执行时间只需要10s,但是由于数据库量增大之后,执行时间变成了60s,而我设置的间隔时间是30s,这样就会出现上次任务还没执行完成,下次任务就开始执行了。所以,在这种情况下,我们要禁止quart的并发操作。
方式1:
spring中将job的concurrent属性设置为false。默认是true 如下:
<bean id="scheduleJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="scheduleBusinessObject"/>
<property name="targetMethod" value="doIt"/>
<property name="concurrent" value="false"/>
</bean>
方式2:
job类上加上注解@DisallowConcurrentExecution。
@DisallowConcurrentExecution
public class HelloQuartz implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
JobDetail detail = jobExecutionContext.getJobDetail();
String name = detail.getJobDataMap().getString("name");
System.out.println("my job name is " + name + " at " + new Date());
}
}
注意:@DisallowConcurrentExecution是对JobDetail实例生效,如果一个job类被不同的jobdetail引用,这样是可以并发执行。
原文链接:https://blog.csdn.net/bicheng4769/article/details/81097305
cron表达式详解
https://www.cnblogs.com/yanghj010/p/10875151.html
Quartz的几个核心概念如下:
Job:代表一个工作,要执行的内容,此接口只有一个方法execute().
JobDetail:代表一个可执行的调度程序,Job是这个可执行调度程序的内容,另外,JobDetail还包含了这个任务调度的方案和策略。
Trigger:代表一个调度参数的配置
Scheduler:代表一个调度容器,可以注册多个JobDetial和Trigger
SchedulerFactory:代表一个调度工厂,用来创建一个scheduler调度器
Quartz执行流程:体现在Spring就是,Job注入到JobDetial,JobDetial注入到Trigger,Trigger注入到Scheduler中
动态配置的调度时间:
https://www.cnblogs.com/laoyeye/p/9352002.html
maven依赖(quartz版本2.2.1)
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
简单实例
主函数
/**
* @(#)quartzMain.java, 2020/7/13.
* <p/>
* Copyright 2020 Netease, Inc. All rights reserved.
* NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package quartz.myQuartz;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
/**
* @author lvhouhou(lvhouhou @ 163.com)
*/
public class quartzMain {
public static void main(String[] args) {
//定义一个JobDetail
JobDetail jobDetail = JobBuilder.newJob(HelloQuartz.class)
//定义name和group
.withIdentity("job1", "group1")
//job需要传递的内容
.usingJobData("name", "sdas")
.build();
//定义一个Trigger
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
//加入 scheduler之后立刻执行
.startNow()
//定时 ,每个1秒钟执行一次
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
//重复执行
.repeatForever()).build();
try {
//创建scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start(); //运行一段时间后关闭
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scheduler.shutdown();
} catch (
SchedulerException e) {
e.printStackTrace();
}
}
}
HelloQuartz 类
/**
* @(#)HelloQuartz.java, 2020/7/13.
* <p/>
* Copyright 2020 Netease, Inc. All rights reserved.
* NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package quartz.myQuartz;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import java.util.Date;
/**
* @author lvhouhou(lvhouhou @ 163.com)
*/
public class HelloQuartz implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) {
JobDetail detail = jobExecutionContext.getJobDetail();
String name = detail.getJobDataMap().getString("name");
System.out.println("my job name is " + name + " at " + new Date());
}
}