Java定时任务调度工具详解之Quartz
Quartz简介
概要
OpenSymphony提供的强大的开源任务调度框架
官网 : http://www.quartz-scheduler.org/
纯Java实现,精细控制排程
特点
强大的调度功能
灵活的应用方式
分布式和集群能力
主要用到的设计模式
Builder模式
Factory模式
组件模式
链式写法
三个核心概念
调度器
任务
触发器
Quartz体系结构
JobDetail: 它包含了任务的实现类,以及类的一些信息;
Trigger: 触发器,它决定这个任务什么时候被调用,这个trigger分为两个分别是SimpleTrigger和CronTrigger
Schedule:调度器,它能定时定频率的执行JobDetail的信息,且通过Schedule将JobDetail和Trigger绑定在一起;
重要组成
Job: 它是一个接口,并且只有一个方法(void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {}),开发者可以实现该接口定义运行任务,它只有一个参数就是JobExecutionContext,
JobExecutionContext类提供了调度上下文的各种信息,所以我们可以传参进去.Job运行时的信息就保存在JobExecutionContext里面的JobDataMap实例中;
JobDetail: 通过JobDetail描述Job的实现类及其它相关的静态信息,例如:Job的名字,描述等等;
JobBuilder: 用来定义或者创建JobDetail的实例;
JobStore: 它也是一个接口,用来保存Job数据的.实现类主要有RemJobStore,JobStoreTx,JobStoreCmt(后两个均将数据保存在数据库中,前一个是将数据保存在内存中)
Trigger: 它是一个类,描述触发Job执行时的时间和触发规则;
TriggerBuilder: 用来定义或者创建触发器的实例;
ThreadPool: 有且仅有一个后台线程在执行;
Schedule: 它是一个调度器,它代表Quartz的一个独立运行容器.Trigger和JobDetail可以注射到Schedule容器中,两者在Schedule中拥有各自的组及名称,组及名称是Schedule查找和定位的某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组及对象也必须唯一,但是JobDetail和Trigger的组和名称可以相同(因为他们是不同类型的).Schedule定义了多个接口方法,允许外部通过组及名称访问它的控制容器中的Trigger和JobDetail;
Calendar: 一个Trigger可以和多个Calendar关联,以排除或包含某些时间点.
监听器: JobListener,TriggerListener,ScheduleListener.
注意:JobDetail已经限定了Job的实例.
编写第一个Quartz任务
让任务每隔两秒钟打印一次Hello Word
QuartzJob类:
代码:
import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/27. */ public class QuartzJob implements Job{ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 System.out.println("Hello Word"); } }
QuartzScheduler类:
代码:
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; /** * Created by gailun on 2017/12/27. */ public class QuartzScheduler { public static void main(String[] args) throws SchedulerException { //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity("myJob","group1").build(); //任务的名称 System.out.println("jobDetail's name : "+jobDetail.getKey().getName()); //任务所在的组,如果不设置任务所在的组时默认DEFAULT System.out.println("jobDetail's group : "+jobDetail.getKey().getGroup()); //任务的实现类 System.out.println("jobDetail's jobClass : "+jobDetail.getClass().getName()); //创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger","group1"). startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); //创建Scheduler实例 SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); //打印执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); scheduler.scheduleJob(jobDetail,trigger); } }
Job定义
实现业务逻辑的任务接口;Job接口非常容易实现,只有一个execute方法,类似TimerTask的run方法,在里面编写业务逻辑
Job实例在Quartz中的生命周期
每次调度器执行Job时,它在调用execute方法前会创建一个新的Job实例.
当调用完成后,关联的Job对象实例会被释放,释放的实例会被垃圾回收机制回收.
JobDetail
JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例.
JobDetail的重要属性:
1.name 它代表着的是任务的名称,在JobDetail中是必须的;
2.group 它代表的是任务所在的组,在JobDetail中也是必须的;
3.jobClass 它代表着的是任务的实现类,就是上面传过来的QuartzJob类,在JobDetail中也是必须的;
4.jobDataMap 它是起到用来传参的作用;
JobExecutionContext是什么?
1.当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;
2.Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据;
JobDataMap是什么?
1.在进行任务调度时JobDataMap存储
在JobExecutionoContext中,非常方便获取;
2.JobDataMap可以用来装载任何可序列化的数据对象,当Job实例对象被执行时这些参数对象会传递给它;
3.JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法用来存取基本数据类型;
获取JobDataMap的两种方式
1.从Map中直接获取
QuartzScheduler1类:
代码:
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; /** * Created by gailun on 2017/12/27. */ public class QuartzScheduler1 { public static void main(String[] args) throws SchedulerException { //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail = JobBuilder.newJob(QuartzJob1.class).withIdentity("myJob") //传入自定义的参数 .usingJobData("message","hello myJob1") .usingJobData("FloatJobValue",3.14F) .build(); //创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") //传入自定义的参数 .usingJobData("message","hello myTrigger1") .usingJobData("DoubleTriggerValue",2.0D) .startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); //创建Scheduler实例 SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); //打印执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); scheduler.scheduleJob(jobDetail,trigger); } }
QuartzJob1类:
代码:
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; /** * Created by gailun on 2017/12/27. */ public class QuartzJob1 implements Job{ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 //打印JobDetail对象的参数 JobKey key = jobExecutionContext.getJobDetail().getKey(); System.out.println("key : "+key); System.out.println("jobDetail name and group are :"+key.getName()+key.getGroup()); //打印Trigger对象的参数 TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey(); System.out.println("triggerKey :"+triggerKey); System.out.println("trigger name and group are:"+triggerKey.getName()+triggerKey.getGroup()); //获取JobDataMap对象 JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); JobDataMap jobDataMap1 = jobExecutionContext.getTrigger().getJobDataMap(); //打印JobDetail对象传入的自定义参数 String jobDetailMessage = jobDataMap.getString("message"); Float floatJobValue = jobDataMap.getFloatValue("FloatJobValue"); //打印Trigger对象传入的自定义参数 String triggerMessage = jobDataMap1.getString("message"); Double doubleTriggerValue = jobDataMap1.getDoubleValue("DoubleTriggerValue"); System.out.println(jobDetailMessage); System.out.println(floatJobValue); System.out.println(triggerMessage); System.out.println(doubleTriggerValue); } }
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; /** * Created by gailun on 2017/12/27. */ public class QuartzJob1 implements Job{ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 //打印JobDetail对象的参数 JobKey key = jobExecutionContext.getJobDetail().getKey(); System.out.println("key : "+key); System.out.println("jobDetail name and group are :"+key.getName()+key.getGroup()); //打印Trigger对象的参数 TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey(); System.out.println("triggerKey :"+triggerKey); System.out.println("trigger name and group are:"+triggerKey.getName()+triggerKey.getGroup()); //第一种获取参数的方法 //获取JobDataMap对象 //JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); //JobDataMap jobDataMap1 = jobExecutionContext.getTrigger().getJobDataMap(); //打印JobDetail对象传入的自定义参数 //String jobDetailMessage = jobDataMap.getString("message"); //Float floatJobValue = jobDataMap.getFloatValue("FloatJobValue"); //打印Trigger对象传入的自定义参数 //String triggerMessage = jobDataMap1.getString("message"); //Double doubleTriggerValue = jobDataMap1.getDoubleValue("DoubleTriggerValue"); //System.out.println(jobDetailMessage); //System.out.println(floatJobValue); //System.out.println(triggerMessage); //System.out.println(doubleTriggerValue); //第二种获取参数的方法 JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap(); String message = mergedJobDataMap.getString("message"); Float floatJobValue = mergedJobDataMap.getFloatValue("FloatJobValue"); Double doubleTriggerValue = mergedJobDataMap.getDoubleValue("DoubleTriggerValue"); System.out.println(message); System.out.println(floatJobValue); System.out.println(doubleTriggerValue); } }
运行结果:
2.Job实现类中添加setter方法对应JobDataMap的键值(Quartz框架默认的JobFactory实现类在初始化job实例对象时会自动地调用这些setter方法)
QuartzJob1类:
代码:
importorg.quartz.Job;
importorg.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; /** * Created by gailun on 2017/12/27. */ public class QuartzJob1 implements Job{ private String message; private Float FloatJobValue; private Double 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; } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 //打印JobDetail对象的参数 JobKey key = jobExecutionContext.getJobDetail().getKey(); System.out.println("key : "+key); System.out.println("jobDetail name and group are :"+key.getName()+key.getGroup()); //打印Trigger对象的参数 TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey(); System.out.println("triggerKey :"+triggerKey); System.out.println("trigger name and group are:"+triggerKey.getName()+triggerKey.getGroup()); System.out.println(message); System.out.println(FloatJobValue); System.out.println(DoubleTriggerValue); } }
QuartzScheduler1类:
代码:
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; /** * Created by gailun on 2017/12/27. */ public class QuartzScheduler1 { public static void main(String[] args) throws SchedulerException { //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail = JobBuilder.newJob(QuartzJob1.class).withIdentity("myJob") //传入自定义的参数 .usingJobData("message","hello myJob1") .usingJobData("FloatJobValue",3.14F) .build(); //创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") //传入自定义的参数 .usingJobData("message","hello myTrigger1") .usingJobData("DoubleTriggerValue",2.0D) .startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); //创建Scheduler实例 SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); //打印执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); scheduler.scheduleJob(jobDetail,trigger); } }
运行结果:
浅谈Trigger Trigger是什么? Quartz中的触发器用来告诉调度程序作业什么时候触发.即Trigger对象是用来触发执行Job的. Quartz框架中的Trigger(如下图)
触发器通用属性
1.JobKey:表示Job实例的标识,触发器被触发时,该指定的Job实例会执行.
2.StartTime:表示触发器的时间表首次被触发的时间.它的值的类型是Java.util.Date.
3.EndTime:指定触发器的不再被触发的时间.它的值的类型是Java.util.Date.
例子:
QuartzScheduler2类:
代码:
importorg.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; /** * Created by gailun on 2017/12/27. */ public class QuartzScheduler2 { public static void main(String[] args) throws SchedulerException { //打印当前的时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail = JobBuilder.newJob(QuartzJob2.class).withIdentity("myJob") .build(); //获取距离当前时间3秒后的时间 date.setTime(date.getTime()+3000); //获取距离当前时间6秒后的时间 Date endTime = new Date(); endTime.setTime(endTime.getTime()+6000); //创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次 Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") //.startNow() .startAt(date) //设置开始时间 .endAt(endTime) //设置结束时间 .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); //创建Scheduler实例 SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
QuartzJob类:
代码:
importorg.quartz.Job;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.Trigger; import org.quartz.TriggerKey; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/27. */ public class QuartzJob2 implements Job{ private String message; private Float FloatJobValue; private Double 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; } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); Trigger trigger = jobExecutionContext.getTrigger(); System.out.println("Start Time Is :"+simpleDateFormat.format(trigger.getStartTime())); System.out.println("End Time Is :"+simpleDateFormat.format(trigger.getEndTime())); JobKey jobKey = trigger.getJobKey(); System.out.println("JobKey : "+jobKey); System.out.println("JobName :"+jobKey.getName()); System.out.println("JobGroup :"+jobKey.getGroup()); } }
运行结果:
SimpleTrigger(它是Trigger的一个分支) SimpleTrigger的作用: 在一个指定时间段内执行一次作业任务或是在指定的时间间隔内多次执行作业任务; SimpleTrigger举例1
QuartzJob3类:
代码:
import org.quartz.Job;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzJob3 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 System.out.println("Hello Word"); } }
QuartzScheduler3类:
代码:
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.SimpleTrigger; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzScheduler3 { public static void main(String[] args) throws SchedulerException { //打印当前的时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail= JobBuilder.newJob(QuartzJob3.class).withIdentity("myJob").build(); //获取距离当前时间4秒之后的具体时间 date.setTime(date.getTime()+4000); //创建一个SimpleTrigger实例,距离当前时间4秒钟后执行且仅执行一次 SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") .startNow() .startAt(date) .build(); //创建Scheduler实例 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
运行结果:
SimpleTrigger举例2(距离当前时间4秒钟后首次执行任务,之后每隔两秒钟重复执行一次任务) QuartzJob4类:
代码:
import org.quartz.Job;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzJob4 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 System.out.println("Hello Word"); } }
QuartzScheduler4类:
代码:
importorg.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.SimpleTrigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzScheduler4 { public static void main(String[] args) throws SchedulerException { //打印当前的时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail= JobBuilder.newJob(QuartzJob3.class).withIdentity("myJob").build(); //获取距离当前时间4秒之后的具体时间 date.setTime(date.getTime()+4000); //创建一个SimpleTrigger实例,距离当前时间4秒钟后首次执行任务,之后每隔两秒钟重复执行一次任务 SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") .startNow() //.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()) .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY)) .startAt(date) .build(); //创建Scheduler实例 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
运行结果:
如果想让这个任务执行4次可以修改为 .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).withRepeatCount(4))
SimpleTrigger举例3(距离当前时间4秒钟后首次执行任务,之后每隔两秒钟重复执行一次任务,直到距离当前时间6秒钟之后为止) QuartzJob4类:
代码:
import org.quartz.Job;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzJob4 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 System.out.println("Hello Word"); } }
QuartzScheduler4类:
代码:
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.SimpleTrigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzScheduler4 { public static void main(String[] args) throws SchedulerException { //打印当前的时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail= JobBuilder.newJob(QuartzJob4.class).withIdentity("myJob").build(); //获取距离当前时间4秒之后的具体时间 date.setTime(date.getTime()+4000); //获取距离当前时间6秒钟之后的具体时间 Date endTime = new Date(); endTime.setTime(endTime.getTime()+6000); //创建一个SimpleTrigger实例,距离当前时间4秒钟后首次执行任务,之后每隔两秒钟重复执行一次任务,直到距离当前时间6秒钟之后为止 SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") .startNow() //.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()) .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY)) //如果想让这个任务执行4次可以修改为 .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).withRepeatCount(4)) .startAt(date) .endAt(endTime) .build(); //创建Scheduler实例 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
运行结果:
需要注意的点
1.重复次数可以为0,正整数或是SimpleTrigger.REPEAT_INDEFINITELY常量值.
2.重复执行间隔必须为0或长整数.
3.一旦被指定了endTime参数,那么它会覆盖重复次数参数的效果.
CronTrigger CronTrigger的作用:基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,比SimpleTrigger更常用. Cron表达式:用于配置CronTrigger实例.是由7个子表达式组成的字符串,描述了时间表的详细信息. 格式: [秒] [分] [小时] [日] [月] [周] [年]
例子1:(每秒钟触发一次任务)
QuartzJob5类:
代码:
importorg.quartz.Job;
importorg.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzJob5 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 System.out.println("Hello Word"); } }
QuartzScheduler5类:
代码:
importorg.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger; 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.SimpleTrigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzScheduler5 { public static void main(String[] args) throws SchedulerException { //打印当前的时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail= JobBuilder.newJob(QuartzJob5.class).withIdentity("myJob").build(); //每秒钟触发一次任务 CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") .withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? *")) .build(); //创建Scheduler实例 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); } }
运行结果:
Cron表达式特殊字符意义对应表
Cron表达式举例
//1. 2017年内每天10点15分触发一次 // 0 15 10 ? * * 2017 //2. 每天的14点整至14点59分59秒,以及18点整至18点59分59秒,每隔5秒钟触发一次 // 0/5 * 14,18 * * ?
通配符说明
Cron表达式小提示 1.'L'和'W'可以一组合使用; 例如:一个月最后一个工作日可以 * * * * LW * ? 2.周字段英文字母不区分大小写即MON与mon相同; 3.利用工具,在线生成(如图);
浅谈Scheduler Scheduler--工厂模式 1.所有的Scheduler实例应该由SchedulerFactory来创建
2.Scheduler的创建方式 SchedulerFactory sfact = new StdSchedulerFactory(); Scheduler scheduler = sfact.getScheduler(); DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance(); Scheduler scheduler = factory.getScheduler(); 3.StdSchedulerFactory 3.1 使用一组参数(Java.util.Properties)来创建和初始化Quartz调度器; 3.2 配置参数一般存储在quartz.properties中; 3.3 调用getScheduler方法就能创建和初始化调度器对象;
4.Scheduler的主要函数 4.1 Date schedulerJob(JobDetail jobDetail,Trigger trigger); 返回的这个时间指的是最近一次的执行时间 4.2 void start(); 启动我们的Scheduler 4.3 void standby(); 让这个Scheduler暂时的挂起
例子:
QuartzJob5类:
代码:
import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzJob5 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //打印当前执行时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current1 Time => "+simpleDateFormat.format(date)); //编写具体的业务逻辑 System.out.println("Hello Word"); } }
QuartzScheduler5类:
代码:
import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; 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.SimpleTrigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by gailun on 2017/12/30. */ public class QuartzScheduler5 { public static void main(String[] args) throws SchedulerException, InterruptedException { //打印当前的时间 Date date = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current2 Time => "+simpleDateFormat.format(date)); //创建一个JobDetail实例,将该实例与QuartzJob Class绑定 JobDetail jobDetail= JobBuilder.newJob(QuartzJob5.class).withIdentity("myJob").build(); //每秒钟触发一次任务 CronTrigger trigger = (CronTrigger)TriggerBuilder.newTrigger() .withIdentity("myTrigger","group1") .withSchedule(CronScheduleBuilder.cronSchedule("* * * * * ? *")) .build(); //1. 2017年内每天10点15分触发一次 // 0 15 10 ? * * 2017 //2. 每天的14点整至14点59分59秒,以及18点整至18点59分59秒,每隔5秒钟触发一次 // 0/5 * 14,18 * * ? //3. 每月周一至周五的10点15分触发一次 //4. 每月最后一天的10点15分触发一次 //5. 每月第三个周五的10点15分触发一次 //创建Scheduler实例 SchedulerFactory schedulerFactory=new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); //开始执行 scheduler.start(); scheduler.scheduleJob(jobDetail,trigger); //Scheduler执行两秒后挂起 Thread.sleep(2000L); scheduler.standby(); //Scheduler挂起3秒后继续执行 Thread.sleep(3000L); scheduler.start(); } }
执行结果:
4.4 void shutdown();
将这个Scheduler关闭了,是完全关闭了Scheduler且不能重新重启了.
shutdown(true)表示等待所有正在执行的Job执行完毕之后,再关闭scheduler
shutdown(false)即shutdown()表示直接关闭scheduler
quartz.properties
文档的位置和加载顺序
先加载工程目录下的quartz.properties;如果工程目录下不存在,则加载jar包下的quartz.properties
组成部分
1.调度器属性
org.quartz.scheduler.instanceName属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名.
org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但这个值必须是在所有调度器实例中是唯一的,尤其是在一个集群当中,作为集群的唯一key.假如你想Quartz帮你生成这个值的话,可以设置为AUTO.
2.线程池属性
threadCount:设置线程数的,必须设置一个值,不要太大;
threadPriority:设置线程的优先级,最小值为1,最大值为10,这个属性的正常值为5;
org.quartz.threadPool.class:常用的线程池
3.作业存储设置
描述了在调度器实例的生命周期中,Job和Trigger信息是如何被存储的.
4.插件配置
满足特定需求用到的Quartz插件的配置.
代码:
# Default Properties file for use by StdSchedulerFactory # to create a Quartz Scheduler Instance, if a different # properties file is not explicitly specified. # # =========================================================================== # Configure Main Scheduler Properties 调度器属性 # =========================================================================== org.quartz.scheduler.instanceName: DefaultQuartzScheduler org.quartz.scheduler.instanceid:AUTO org.quartz.scheduler.rmi.export: false org.quartz.scheduler.rmi.proxy: false org.quartz.scheduler.wrapJobExecutionInUserTransaction: false # =========================================================================== # Configure ThreadPool 线程池属性 # =========================================================================== #线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求) org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool #指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适) org.quartz.threadPool.threadCount: 10 #设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5) org.quartz.threadPool.threadPriority: 5 #设置SimpleThreadPool的一些属性 #设置是否为守护线程 #org.quartz.threadpool.makethreadsdaemons = false #org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true #org.quartz.threadpool.threadsinheritgroupofinitializingthread=false #线程前缀默认值是:[Scheduler Name]_Worker #org.quartz.threadpool.threadnameprefix=swhJobThead; # 配置全局监听(TriggerListener,JobListener) 则应用程序可以接收和执行 预定的事件通知 # =========================================================================== # Configuring a Global TriggerListener 配置全局的Trigger监听器 # MyTriggerListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串) # =========================================================================== #org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass #org.quartz.triggerListener.NAME.propName = propValue #org.quartz.triggerListener.NAME.prop2Name = prop2Value # =========================================================================== # Configuring a Global JobListener 配置全局的Job监听器 # MyJobListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串) # =========================================================================== #org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass #org.quartz.jobListener.NAME.propName = propValue #org.quartz.jobListener.NAME.prop2Name = prop2Value # =========================================================================== # Configure JobStore 存储调度信息(工作,触发器和日历等) # =========================================================================== # 信息保存时间 默认值60秒 org.quartz.jobStore.misfireThreshold: 60000 #保存job和Trigger的状态信息到内存中的类 org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore # =========================================================================== # Configure SchedulerPlugins 插件属性 配置 # =========================================================================== # 自定义插件 #org.quartz.plugin.NAME.class = com.swh.MyPluginClass #org.quartz.plugin.NAME.propName = propValue #org.quartz.plugin.NAME.prop2Name = prop2Value #配置trigger执行历史日志(可以看到类的文档和参数列表) org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy} org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9} #配置job调度插件 quartz_jobs(jobs and triggers内容)的XML文档 #加载 Job 和 Trigger 信息的类 (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin) org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin #指定存放调度器(Job 和 Trigger)信息的xml文件,默认是classpath下quartz_jobs.xml org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml #org.quartz.plugin.jobInitializer.overWriteExistingJobs = false org.quartz.plugin.jobInitializer.failOnFileNotFound = true #自动扫描任务单并发现改动的时间间隔,单位为秒 org.quartz.plugin.jobInitializer.scanInterval = 10 #覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况 org.quartz.plugin.jobInitializer.wrapInUserTransaction = false # =========================================================================== # Sample configuration of ShutdownHookPlugin ShutdownHookPlugin插件的配置样例 # =========================================================================== #org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin #org.quartz.plugin.shutdownhook.cleanShutdown = true # # Configure RMI Settings 远程服务调用配置 # #如果你想quartz-scheduler出口本身通过RMI作为服务器,然后设置“出口”标志true(默认值为false)。 #org.quartz.scheduler.rmi.export = false #主机上rmi注册表(默认值localhost) #org.quartz.scheduler.rmi.registryhost = localhost #注册监听端口号(默认值1099) #org.quartz.scheduler.rmi.registryport = 1099 #创建rmi注册,false/never:如果你已经有一个在运行或不想进行创建注册 # true/as_needed:第一次尝试使用现有的注册,然后再回来进行创建 # always:先进行创建一个注册,然后再使用回来使用注册 #org.quartz.scheduler.rmi.createregistry = never #Quartz Scheduler服务端端口,默认是随机分配RMI注册表 #org.quartz.scheduler.rmi.serverport = 1098 #true:链接远程服务调度(客户端),这个也要指定registryhost和registryport,默认为false # 如果export和proxy同时指定为true,则export的设置将被忽略 #org.quartz.scheduler.rmi.proxy = false
Spring和Quartz的整合
pom文件需要引入的依赖:
spring使用Quartz配置作业:
两种方式
MethodInvokingJobDetailFactoryBean
调用myBean的printMessage方法
JobDetailFactoryBean
spring的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
default-lazy-init="true">
<!-- 通过mvc:resources设置静态资源,这样servlet就会处理这些静态资源,而不通过控制器 -->
<!-- 设置不过滤内容,比如:css,jquery,img 等资源文件 -->
<mvc:resources location="/*.html" mapping="/**.html" />
<mvc:resources location="/css/*" mapping="/css/**" />
<mvc:resources location="/js/*" mapping="/js/**" />
<mvc:resources location="/images/*" mapping="/images/**" />
<!-- 设定消息转换的编码为utf-8防止controller返回中文乱码 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
<!-- 添加注解驱动 -->
<mvc:annotation-driven />
<!-- 默认扫描的包路径 -->
<context:component-scan base-package="com.imooc.springquartz" />
<!-- mvc:view-controller可以在不需要Controller处理request的情况,转向到设置的View -->
<!-- 像下面这样设置,如果请求为/,则不通过controller,而直接解析为/index.jsp -->
<mvc:view-controller path="/" view-name="index" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView"></property>
<!-- 配置jsp路径前缀 -->
<property name="prefix" value="/"></property>
<!-- 配置URl后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myBean" />
<property name="targetMethod" value="printMessage" />
</bean>
<bean id="firstComplexJobDetail"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass"
value="com.imooc.springquartz.quartz.FirstScheduledJob" />
<property name="jobDataMap">
<map>
<entry key="anotherBean" value-ref="anotherBean" />
</map>
</property>
<property name="Durability" value="true"/>
</bean>
<!-- 距离当前时间1秒之后执行,之后每隔两秒钟执行一次 -->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail"/>
<property name="startDelay" value="1000"/>
<property name="repeatInterval" value="2000"/>
</bean>
<!-- 每隔5秒钟执行一次 -->
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail"/>
<ref bean="firstComplexJobDetail"/>
</list>
</property>
<property name="triggers">
<list>
<ref bean="mySimpleTrigger"/>
<ref bean="myCronTrigger"/>
</list>
</property>
</bean>
</beans>