简介
Quartz是一个任务调度框架,是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。
比如你遇到这样的问题:
- 每个月29号,信用卡自动还款
- 每年4月1日给自己暗恋女神发一封匿名贺卡
- 每个1小时,备份一下自己的学习笔记
这些问题总结起来就是:在某一个有规律的时间点做某事。并且时间的触发条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事情。
Quartz就是来专门干这个事情的,你给它一个触发条件的定义,它负责到指定时间点,触发对应的Job起来干活。如果应用程序需要在给定时间执行任务,或者如果系统有连续维护作业,那么Quartz是最理想的解决方案。
特点
-
作业调度:作业被安排在一个给定的触发时间运行。触发器可以使用下列指令的组合来创建:
- 在一天中的某个时间(到毫秒)
- 在一周的某几天
- 在每月的某一天
- 在一年中的某些日期
- 不在注册的日历中列出的特定日期(如商业节假日除外)
- 重复特定次数
- 重复进行,直到一个特定的时间/日期
- 无限重复
- 重复的延迟时间间隔
-
作业持久性:Quartz的设计包括一个作业存储接口,有多种实现。
- 通过使用包含JDBCJobStore,所有的作业和触发器配置为『非挥发性』都存储在通过JDBC关系数据库
- 通过使用包含的RAMJobStore,所有的作业和触发器存储在RAM,因此不计划执行仍然存在——但这是无需使用外部数据库的优势
配置
#名为:quartz.properties,放在classpath下,如果没有此配置则按默认配置启动
# 指定调度器名称,非实现类
org.quartz.scheduler.instanceName = DefaultQuartzScheduler04
# 指定线程池实现类
org.quartz.threadPool.class = org.quartz.simple.SimpleThreadPool
# 线程池线程数量
org.quartz.threadPool.threadCount = 10
# 优先级,默认5
org.quartz.threadPool.threadPriority = 5
# 非持久化job
org.quartz.jobStore.class = org.quartz.simple.RAMJobStore
核心类说明
Scheduler
Scheduler:调度器,所有的调度都由它控制,Scheduler就是Quartz的大脑,所有任务都是由它来设置。
Schduler包含两个重要的组件:JobStore和ThreadPool
- JobStore是会来存储运行时信息的,包括Trigger,Schduler,JobDetail,业务锁等
- ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务都会由线程池执行
SchdulerFactory,顾名思义就是用来创建Schduler,有两个实现DiretSchedulerFactory和StdSchdulerFactory
。前者可以用来在代码里定制你自己的Schduler参数。后者是直接读取classpath下的quartz.properties(不存在就使用默认值)配置来实例化Schduler。通常来讲,使用StdSchdulerFactory也就足够了。
SchdulerFactory本身是支持创建stub的,可以用来管理远程的Scheduler,功能和本地一致。
Trigger
SimpleTrigger
指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。
它适合的任务类似于:9:00开始,每隔1小时,执行一次
它的属性有:
- repeatInterval:重复间隔
- repeatCount:重复次数。实际执行次数是repeatCount + 1。因为在startTime的时候一定会执行一次。
示例:
SimpleScheduleBuiler.simpleSchedule()
.withIntervalSeconds(10)//每隔10秒执行一次
.repeatForever()//永远执行
build();
SimpleScheduleBuiler.simpleSchedule()
.withIntervalInMinutes(3)//每隔3分钟执行一次
.withRepeatCount(3)//执行3次
build();
CalendarIntervalTrigger
类似于SimpleTrigger,指定从某一个时间开始,以一定的时间间隔执行的任务。但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。
CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInDays(2)//每2天执行一次
.build();
CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInWeeks(1)//每周执行一次
.build();
DailyTimeIntervalTrigger
指定每天的某个时间段内,以一定的时间间隔执行任务,并且它可以支持指定星期。它合适的任务类似于:指定每天9:00至18:00,每隔70秒执行一次,并且只要周一至周五执行。
它的属性有:
- startTimeOfDay:每天开始时间
- endTimeOfDay:每天结束时间
- daysOfWeek:需要执行的星期
- interval:执行间隔
- intervalUnit:执行间隔的单位(秒,分钟,小时,天,月,年,星期)
- repeatCount:重复次数
示例:
DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))//每天9:00开始
.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(18, 0))//每天18:00结束
.onDaysOfTheWeek(DateBuilder.MONDAY, DateBuilder.TUESDAY)//周一和周二
.withIntervalInHours(1)//每隔1小时执行一次
.withRepeatCount(100)//最多重复100次(实际执行101次)
.build();
DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0))//每天9:00开始
.endingDailyAfterCount(10)//每天执行10次后结束,这个方法实际上根据startTimeOfDay+interval*count=endTimeOfDay
.onDaysOfTheWeek(DateBuilder.MONDAY, DateBuilder.TUESDAY)//周一和周二
.withIntervalInHours(1)//每隔1小时执行一次
.build();
CronTrigger
适合于更复杂的任务,它支持类型Linux Cron的语法(并且更强大)。基本上它覆盖了以上三个Trigger的绝大部分能力(但不是全部)。它适合的任务类似于:每天0:00,9:00,18:00各执行一次。它的属性只有一个:Cron表达式
示例:
CronScheduleBuilder.cronSchedule("0/10 * * * * ?").build();
简单使用
依赖:
<dependencies>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.3</version>
</dependency>
</dependencies>
Job
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//创建工作详情
JobDetail jobDetail = jobExecutionContext.getJobDetail();
//获取工作的名称
String name = jobDetail.getKey().getName();//任务明
String group = jobDetail.getKey().getGroup();//任务group
String data = jobDetail.getJobDataMap().getString("data");//任务中的数据
System.out.println("job执行,job名:" + name + " group:" + group + " data:" + data + new Date());
}
}
private static void test01() throws SchedulerException {
//创建scheduler调度器,核心组件
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定义一个Trigger,触发条件类
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
//创建触发器trigger
Trigger trigger = triggerBuilder.withIdentity("trigger1", "group1")//定义name/group
.startNow()//一旦加入scheduler立即生效,即开始时间
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)//一秒执行一次
.repeatForever())//一直执行,直到结束
//可以设置结束时间,如果不设置,则一直执行
.endAt(new GregorianCalendar(2021,5,5,16,7,0).getTime())
.build();
//定义一个JobDetail
//定义Job类为MyJob类,这是真正的执行逻辑所在
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("测试任务1", "test")//定义name/group
.usingJobData("data", "jobData_xxxxxx")//定义属性,存储数据
.build();
//调度器中假如任务和触发器
scheduler.scheduleJob(job, trigger);
//启动任务调度
scheduler.start();
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
//关闭调度器
scheduler.shutdown();
}
```