一、浅谈Job&JobDetail
JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员属性变量,它用来存储特定的Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例
1.1 重要属性
name jobClass group jobDataMap 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是什么
在进行任务调度时JobDataMap存储在JobExecutionContext中,非常方便获取JobDataMap可以用来装在任何可序列化的数据对象,job实例对象被执行时,这些参数对象会传递给它JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法来存取基本数据类型2.2 获取JobDataMap的两种方式
从Map中直接获取Job实现类中添加setter方法对应JobDataMap的键值(Quartz框架默认的JobFactory实现类在初始化job实例对象时会自动的调用这些setter方法 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 触发器通用属性:
JobKey -- 表示job实例的标识,触发器触发时,该指定的job实例会执行StartTime -- 表示触发器的时间表首次被触发时间,它的值的类型是Java.util.DateEndTime -- 指定触发器的不再被触发的时间,它的值的类型是Java.util.Date
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
使用一组参数(java.util.properties)来创建和初始化Quartz调度器 配置参数 一般存储在quartz.properties中 调用getScheduler方法就能创建和初始化调度起对象
4.3 scheduler的主要方法
Date scheduleJob(JobDetail var1, Trigger var2) void start() -- 重启 void standby() -- 挂起 void shutdown() -- 关闭,不可被重启
4.4 quart.properties -- 加载顺序,先去src目录查找,如果没有会去quartz的jar包中查找quartz.properties文件
4.4.1 组成部分
调度器属性 线程池属性 作业存储设置 插件配置
4.4.2 线程池属性
threadCount threadPriority 1-10,正常默认5 org.quartz.threadPool.class
五、给大家提供一个方便的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<String, Object> 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<Trigger> 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<String, Object> 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; } }