一、浅谈Job&JobDetail
JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员属性变量,它用来存储特定的Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例
1.1 重要属性
package com.demo;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 创建一个jobdetail实例
JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob", "1").build();
System.out.println("jobDetail's name : "+jobDetail.getKey().getName());
System.out.println("jobDetail's group : "+jobDetail.getKey().getGroup());
System.out.println("jobDetail's jobClass : "+jobDetail.getJobClass().getName());
// 创建一个trigger实例,定义该job立即执行,并且每隔2秒钟执行一次,直到永远
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();
// 创建Scheduler实例
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
scheduler.start(); //执行
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time is"+ sf.format(date)+"HelloScheduler");
scheduler.scheduleJob(jobDetail,trigger); //绑定
}
}
package com.demo;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time is"+ sf.format(date));
System.out.println();
// 编写具体的业务逻辑
System.out.println("Hello World!");
}
}
1.2 JobExecutionContext
当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;
Job不能通过JoExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据
二、 JobDataMap
2.1 JobDataMap是什么
2.2 获取JobDataMap的两种方式
package com.demo;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloJob implements Job {
private String message;
private Float FloatJobValue;
private Double DoubleTriggerValue;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 打印当前的执行时间
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time is" + sf.format(date));
System.out.println();
// 获取jobKey信息
JobKey key = jobExecutionContext.getJobDetail().getKey();
System.out.println("My Job name and group are " + key.getName() + ":" + key.getGroup());
// 获取triggerKey信息
TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
System.out.println("My Trigger name and group are " + triggerKey.getName() + ":" + triggerKey.getGroup());
// 获取自己输入的信息
//mergedDataMap 包含dataMap与tdataMap,如果两者有相同的key,trigger的key的信息会覆盖带你job的信息
// JobDataMap mergedDataMap = jobExecutionContext.getMergedJobDataMap();
//job的map信息
// JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
//trigger的map信息
// JobDataMap tdataMap = jobExecutionContext.getTrigger().getJobDataMap();
// String jobMsg = mergedDataMap.getString("message");
// float jobFloatValue = mergedDataMap.getFloat("FloatJobValue");
// String triggerMsg = mergedDataMap.getString("message");
// double doubleTriggerValue = mergedDataMap.getDouble("DoubleTriggerValue");
System.out.println("jobMsg is " + message);
System.out.println("jobFloatValue is " + FloatJobValue);
// System.out.println("triggerMsg is " + triggerMsg);
System.out.println("doubleTriggerValue is " + DoubleTriggerValue);
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Float getFloatJobValue() {
return FloatJobValue;
}
public void setFloatJobValue(Float floatJobValue) {
FloatJobValue = floatJobValue;
}
public Double getDoubleTriggerValue() {
return DoubleTriggerValue;
}
public void setDoubleTriggerValue(Double doubleTriggerValue) {
DoubleTriggerValue = doubleTriggerValue;
}
}
package com.demo;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import java.text.SimpleDateFormat;
import java.util.Date;
public class HelloScheduler {
public static void main(String[] args) throws SchedulerException {
// 创建一个jobdetail实例
JobDetail jobDetail = JobBuilder
.newJob(HelloJob.class)
.withIdentity("myJob", "1")
.usingJobData("message", "hello myJob1") //存储在JobdateMap中
.usingJobData("FloatJobValue", 3.14F)
.build();
// 创建一个trigger实例,定义该job立即执行,并且每隔2秒钟执行一次,直到永远
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTrigger", "1")
.usingJobData("message", "hello myTrigger1")
.usingJobData("DoubleTriggerValue", 2.0D)
.startNow()
.withSchedule(
SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever()
)
.build();
// 创建Scheduler实例
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
scheduler.start(); //执行
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current Time is" + sf.format(date) + "HelloScheduler");
scheduler.scheduleJob(jobDetail, trigger); //绑定
}
}
三、 浅谈Tigger
3.1 Quartz框架中的Trigger,用到比较多的是CronTriggerImpl、SimpleTriggerImpl
3.2 触发器通用属性:
3.3 SimpleTrigger的作用
在一个指定时间段内执行一次作业任务,或是在指定的时间间隔内多次执行作业任务
3.3.1 SimpleTrigger需要注意的点
重复次数可以为0,正整数或者是SimpleTrigger.REPEAT_INDEFINITELY(无穷)常量值
重复执行间隔必须为0或者长整数
一旦指定了endTime参数,那么它会覆盖重复次数参数的效果
3.4 CronTrigger
3.4.1 CronTrigger的作用:基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,比SimpleTrigger更常用
3.4.2 Cron表达式
用于配置CronTrigger实例
是由7个字表达式组成的字符串,描述了时间表的详细信息
格式:[秒] [分] [时] [日] [月] [周] [年]
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1)*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。
(2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
(3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三
3.4.23 常用表达式
(1)0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED 表示每个星期三中午12点
(7)0 0 12 * * ? 每天中午12点触发
(8)0 15 10 ? * * 每天上午10:15触发
(9)0 15 10 * * ? 每天上午10:15触发
(10)0 15 10 * * ? * 每天上午10:15触发
(11)0 15 10 * * ? 2005 2005年的每天上午10:15触发
(12)0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
(18)0 15 10 15 * ? 每月15日上午10:15触发
(19)0 15 10 L * ? 每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
四、 浅谈Scheduler
4.1 回顾Quartz的三个核心概念
4.2 Scheduler创建方式 -- StdSchedulerFactory
4.3 scheduler的主要方法
4.4 quart.properties -- 加载顺序,先去src目录查找,如果没有会去quartz的jar包中查找quartz.properties文件
4.4.1 组成部分
4.4.2 线程池属性
五、给大家提供一个方便的Quartz工具类
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.quartz.CalendarIntervalScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
public class QuartzManager {
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
* @Description: 添加一个定时任务
* @param jobName
* 任务名
* @param jobGroupName
* 任务组名,传null使用默认任务组名
* @param jobClass
* 任务
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名,传null使用默认触发器名
* @param time
* 时间
* @param isClear
* 是否是清除任务
* @param dataMap
* jobClass需要的参数
*/
public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class extends Job> jobClass, String time, boolean isClear, Map dataMap) {
try {
// 获取调度任务工厂
Scheduler scheduler = schedulerFactory.getScheduler();
// 创建一个JobDetail
JobDataMap jobDataMap = new JobDataMap(dataMap);
JobDetail job = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).usingJobData(jobDataMap)
.build();
// 创建一个CronTrigger
Trigger trigger = null;
TriggerBuilder builder = TriggerBuilder.newTrigger();
builder.withIdentity(triggerName, triggerGroupName);
if (!isClear) {
builder.startNow();
builder.withSchedule(SimpleScheduleBuilder.repeatMinutelyForever(Integer.parseInt(time)));
} else {
String startTime = DateUtils.parseDate(new Date(), "yyyyMMdd") + " "
+ dataMap.get("autoClearStartTime");
builder.startAt(new SimpleDateFormat("yyyyMMdd HH:mm:ss").parse(startTime));
builder.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInDays(Integer.parseInt(time)));
}
trigger = builder.build();
// 将JobDetail和CronTrigger加入调度任务
scheduler.scheduleJob(job, trigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 修改一个任务
*
* @param jobName
* 任务名
* @param jobGroupName
* 任务组名
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
* @param cron
* 定时表达式
* @param dataMap
* jobClass需要的参数
*/
public static void modifyJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
Class extends Job> jobClass, String minute, boolean isCron, Map dataMap) {
try {
// 删除原有的定时任务
removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
// 添加新的定时任务
addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, minute, isCron, dataMap);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description: 移除一个任务
*
* @param jobName
* 任务名
* @param jobGroupName
* 任务组名
* @param triggerName
* 触发器名
* @param triggerGroupName
* 触发器组名
*/
public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
Scheduler scheduler = schedulerFactory.getScheduler();
// 找到对应的触发器
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
// 停止触发器
scheduler.pauseTrigger(triggerKey);
// 移除触发器
scheduler.unscheduleJob(triggerKey);
// 删除任务
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public static void startJobs() {
try {
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public static void shutdownJobs() {
try {
Scheduler scheduler = schedulerFactory.getScheduler();
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:检查Job运行状态
*/
public static boolean checkJobsRunStatus(String triggerName, String triggerGroupName) {
try {
Scheduler scheduler = schedulerFactory.getScheduler();
// 找到对应的触发器
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
TriggerState triggerState = scheduler.getTriggerState(triggerKey);
String state = triggerState.name();
if(TriggerState.NORMAL.name().equals(state) || TriggerState.BLOCKED.name().equals(state) || TriggerState.COMPLETE.name().equals(state)){
return true;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return false;
}
}