Quartz是一个强大任务调度框架,应用场景例如
- 餐厅系统会在每周四晚上的22点自动审核并生成报表
- 人事系统会在每天早晨8点给有待办的人员自动发送Email提醒
一、简单使用(重复执行)
1.引入quartz框架pom依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
2.创建HelloJob实现Job接口
public class HelloJob implements Job{
private static final SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Date now = new Date();
String currentTime = sdf.format(now);
System.out.println("执行时间为:"+currentTime);
}
}
3.创建HelloScheduler触发任务
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//创建jobDetail绑定HelloJob
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob","myGroup").build();
//创建触发器trigger每个2秒执行一次,一直执行
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "myGroup").startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever()).build();
//创建调度者工厂
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
//创建调度者
Scheduler scheduler = schedulerFactory.getScheduler();
//启动调度器
scheduler.start();
//设置调度任务
scheduler.scheduleJob(jobDetail, trigger);
}
}
执行结果:
执行时间为:2019-04-15 23:45:41
23:45:43.388 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.xuxu.quartz.HelloJob
23:45:43.388 [DefaultQuartzScheduler_Worker-9] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
23:45:43.388 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
执行时间为:2019-04-15 23:45:43
23:45:45.387 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.xuxu.quartz.HelloJob
23:45:45.387 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
23:45:45.391 [DefaultQuartzScheduler_Worker-10] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
执行时间为:2019-04-15 23:45:45
二、定时执行使用cron表达式确定时间
1同上引入pom依赖
2创建HelloJob实现job接口,任务执行时输出时间
public class HelloJob implements Job{
private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
Date now = new Date();
String currentDate = sdf.format(now);
System.out.println("现在时间是:"+currentDate+":开始执行任务生成表格,或者发送邮件");
}
}
3创建触发类CronScheduler
public class CronScheduler {
public static void main(String[] args) throws Exception {
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob").build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger")
//cron表达式 这里定义的是4月16日早上9点21分开始执行
.withSchedule(CronScheduleBuilder.cronSchedule("0 21 9 16 4 ? *"))
.build();
SchedulerFactory factory = new StdSchedulerFactory();
//创建调度器
Scheduler scheduler = factory.getScheduler();
//启动调度器
scheduler.start();
//jobDetail和trigger加入调度
scheduler.scheduleJob(jobDetail, trigger);
}
}
这里通过cron表达式确定时间规则
一般我们会使用
cron生成器
,地址是
http://cron.qqe2.com/
执行结果如下
现在时间是:2019-04-16 09:21:00:开始执行任务生成表格,或者发送邮件
Quartz的3大API
Job
JobDetail & Job & JobDataMap
JobDetail
是任务的定义,而
Job
是任务的执行逻辑。在JobDetail里会引用一个Job Class定义。每一个JobDetail都会有一个
JobDataMap
。JobDataMap本质就是一个Map的扩展类,只是提供了一些更便捷的方法,比如getString()之类的。
public class CronScheduler {
public static void main(String[] args) throws Exception {
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
//添加jobname,jobgroup
.withIdentity("myJob","myGroup")
//jobDataMap信息
.usingJobData("message","this is a message")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("cronTrigger")
//cron表达式 这里定义的是4月16日早上9点21分开始执行
.withSchedule(CronScheduleBuilder.cronSchedule("0 00 10 16 4 ? *"))
.build();
SchedulerFactory factory = new StdSchedulerFactory();
//创建调度器
Scheduler scheduler = factory.getScheduler();
//启动调度器
scheduler.start();
//jobDetail和trigger加入调度
scheduler.scheduleJob(jobDetail, trigger);
}
}
public class HelloJob implements Job{
private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Date now = new Date();
String currentDate = sdf.format(now);
JobDetail jobDetail = jobExecutionContext.getJobDetail();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
JobKey jobKey = jobDetail.getKey();
String jobName = jobKey.getName();
String group = jobKey.getGroup();
String message = (String) jobDataMap.get("message");
System.out.println("现在时间是:"+currentDate+":开始执行任务生成表格,或者发送邮件");
System.out.println("jobName---"+jobName);
System.out.println("group---"+group);
System.out.println("message---"+message);
}
}
现在时间是:2019-04-16 10:00:00:开始执行任务生成表格,或者发送邮件
jobName---myJob
group---myGroup
message---this is a message
Tigger
1.startTime和endTime
有时候我们希望一个定时任务在一定的时间内是每天执行,比如2017年11月24日到2017年12月15日之间执行,这时候我们就要使用startTime和endTime来限定事件范围了。例子中我们把时间规定在几秒钟之内运行,方便查看效果。
public class HelloJob implements Job{
private static final SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Date now = new Date();
String currentTime = sdf.format(now);
System.out.println("执行时间为:"+currentTime);
}
}
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
//创建jobDetail绑定HelloJob
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob","myGroup").build();
//设定开始时间,结束时间确定范围
Date triggerStartTime = new Date();
//3秒后开始执行
triggerStartTime.setTime(triggerStartTime.getTime()+3000);
Date triggerEndTime = new Date();
//10秒后结束执行
triggerEndTime.setTime(triggerEndTime.getTime()+10000);
//创建触发器trigger每个2秒执行一次,一直执行
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "myGroup")
.startAt(triggerStartTime)
.endAt(triggerEndTime)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever()).build();
//创建调度者工厂
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
//创建调度者
Scheduler scheduler = schedulerFactory.getScheduler();
//启动调度器
scheduler.start();
//设置调度任务
scheduler.scheduleJob(jobDetail, trigger);
}
}
3秒后执行,10秒内结束执行
如下
执行时间为:2019-04-16 10:36:09
执行时间为:2019-04-16 10:36:11
执行时间为:2019-04-16 10:36:13
执行时间为:2019-04-16 10:36:15
2.BaseCalndar
此calendar不是java.util.Calendar,calendar是为了补充Trigger的时间,可以排除或加入一下特定的时间。Quartz 的 Calender 专门用于屏闭一个时间区间,使 Trigger 在这个区间中不被触发。
- AnnualCalendar:排除每一年中指定的一天或者多少天 ,精度是天
- CronCalendar:使用表达式排除某些时间段不执行,精度取决于Cron表达式,最大精度到秒
- DailyCalendar:指定的时间范围内的每一天不执行,指定每天的时间段,格式是HH:MM[:SS[:mmm]]。也就是最大精度可以到毫秒。
- HolidayCalendar:排除节假日,精度到天
- MonthlyCalendar:排除月份中的数天,可选值为1-31。精度是天
- WeeklyCalendar:排除星期中的一天或多天,可选值比如为java.util.Calendar.SUNDAY,精度是天。
这里使用CronCalendar排除
public class HelloJob implements Job{
private static final SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Date now = new Date();
String currentTime = sdf.format(now);
System.out.println("执行时间为:"+currentTime);
}
}
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException, ParseException {
//创建jobDetail绑定HelloJob
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob","myGroup").build();
//创建触发器trigger每个2秒执行一次,一直执行
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "myGroup")
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever())
//将calendar排除规则绑定到触发器
.modifiedByCalendar("myCalendar")
.build();
//创建调度者工厂
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
//创建调度者
Scheduler scheduler = schedulerFactory.getScheduler();
CronCalendar calendar = new CronCalendar("* * 0-12,18-23 ? * *");
//向Scheduler注册日历
scheduler.addCalendar("myCalendar", calendar, false, false);
//启动调度器
scheduler.start();
//设置调度任务
scheduler.scheduleJob(jobDetail, trigger);
}
}
11:39:12.270 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
11:39:12.381 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
上面指定的是0-12 18-23不执行发现12点之前没有执行
Trigger的实现类
1CalendarIntervalTrigger
:
是一个具体的Trigger,用来触发基于定时重复的JobDetail。
Trigger将会每隔N个calendar在trigger中定义的时间单元触发一次。这个trigger不适合使用SimpleTrigger完成(例如由于每一个月的时间不是固定的描述),也不适用于CronTrigger(例如每5个月)。
相较于SimpleTrigger有两个优势:1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。 2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。
它适合的任务类似于:9:00 开始执行,并且以后每周 9:00 执行一次
它的属性有:
- interval 执行间隔
- intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)
CalendarIntervalScheduleBuilder
.calendarIntervalSchedule()
.withIntervalInDays(1) //每天执行一次
//.withIntervalInHours(1)
//.withIntervalInMinutes(1)
//.withIntervalInMonths(1)
//.withIntervalInSeconds(1)
//.withIntervalInWeeks(1)
//.withIntervalInHours(1)
.build()
2DailyTimeIntervalTrigger
指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。
它适合的任务类似于:指定每天9:00 至 18:00 ,每隔70秒执行一次,并且只要周一至周五执行。
它的属性有:
- startTimeOfDay 每天开始时间
- endTimeOfDay 每天结束时间
- daysOfWeek 需要执行的星期
- interval 执行间隔
- intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)
- repeatCount 重复次数
public static void main(String[] args) throws SchedulerException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//1.创建一个jobDetail的实例,将该实例与HelloJob Class绑定
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "group1") //定义name 和 group
.build();
//2.创建一个Trigger触发器的实例
Trigger simpleTrigger = TriggerBuilder.newTrigger()
.withIdentity("zhlTrigger")
.withSchedule(
DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0)) //每天8:00开始
.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(17, 0)) //17:00 结束
.onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行
.withIntervalInHours(1) //每间隔1小时执行一次
.withRepeatCount(100) //最多重复100次(实际执行100+1次)
)
.modifiedByCalendar("holidays") //将我们设置好的Calander与trigger绑定
.build();
//3.创建schedule实例
StdSchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
System.out.println("现在的时间 :"+sf.format(new Date()));
System.out.println();
System.out.println("最近的一次执行时间 :"+sf.format(scheduler.scheduleJob(jobDetail,simpleTrigger))); //scheduler与jobDetail、trigger绑定,并打印出最近一次执行的事件
scheduler.start();
}
Scheduler
——工厂模式:
所有的Scheduler实例应该由SchedulerFactory来创建,一般包含:StdSchedulerFactory、DirectSchedulerFactory(参数信息需要在代码中维护故不常用)。
StdSchedulerFactory使用一组参数来创建和初始化Quartz调度器,配置参数一般存储在quartz.properties文件中,调用getScheduler方法就能创建和初始化调度器对象。
Scheduler的主要函数:
Data scheduleJob(JobDetail jobDetail,Trigger trigger);
void start();——启动Scheduler;
void standby();——将Scheduler暂时挂起,可以用start()继续执行任务;
void shutDown()关闭Scheduler且不能被重启;示例代码如下: