1.概要
Quartz是由OpenSymphony提供的强大的开源任务调度框架。官网地址:http://www.quartz-scheduler.org/,纯Java实现。
- 强大的调度功能:很容易与Spring集成,提供调度运行环境的持久化机制,保存并恢复任务调度现场。即使系统因故障关闭,任务调度现场数据也不会丢失;
- 灵活的应用方式:允许灵活的定义触发器的调度时间表,并可以对触发器和任务进行关联映射,提供了组件式的监听器、各种插件、线程池等功能,支持任务和调度的多种组合方式、支持调度数据的多种存储方式,支持分布式和集群操作;
- 主要用到的设计模式:Builder模式、Factory模式、组件模式、链式写法;
- 核心概念:调度器——负责定期、定时、定频率的去执行任务;任务——具体的业务逻辑;触发器——调度器调度任务的时间;
- 重要组成:Job——接口且可以接收参数;JobDetail——Job的实现类和相关的静态信息;JobBuilder——定义或者创建JobDetail的实例;JobStore——用来保存Job数据;Trigger——描述触发Job执行时的时间触发规则;TriggerBuilder——定义或者创建触发器的实例;ThreadPool——线程池Job运行的基础设施;Scheduler——Quartz独立运行的容器;Calendar——一个Trigger可以和多个Calendar关联,以排除或者包含某些时间点;监听器——JobListener、TriggerListener、SchedulerLIstener监听对应的组件。
2.Quartz的基本使用
1.每两秒钟打印一次Hello World:
创建Job实现类HelloJob
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class HelloJob implements Job{ @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { //打印当前执行时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("任务执行时间为:"+sf.format(startTime)); System.out.println("Hello World"); } }
创建Job测试类HelloScheduler
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; 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; public class HelloScheduler { public static void main(String[] args) throws SchedulerException { // 创建一个JobDetail实例与HelloJob类绑定 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob", "group1").build(); // 创建一个Trigger实例,定义该Job立即执行,且每隔两秒钟执行一次直到永远 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "group1").startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); //创建scheduler实例 SchedulerFactory sFactory = new StdSchedulerFactory(); Scheduler scheduler = sFactory.getScheduler(); scheduler.start(); //打印当前时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("打印当前时间:"+sf.format(startTime)); scheduler.scheduleJob(jobDetail,trigger); } }
2.浅谈Job&JobDetail
Job:实现业务逻辑的任务接口,job接口非常容易实现,只有一个execute方法,类似TimerTask的run方法,在里面编写业务逻辑。Job在Quartz中的生命周期:每次调度器执行Job时,它在调用execute方法前会创建一个新Job实例;当调用完成后,关联的job对象实例会被释放,释放的实例会被垃圾回收机制回收。JobDetail为job提供了很多设置属性name、group、jobClass、jobDataMap(用来存储特定Job实例的状态信息),调度器需要借助JobDetail对象来添加Job实例。
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; 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; public class HelloScheduler { public static void main(String[] args) throws SchedulerException { // 创建一个JobDetail实例与HelloJob类绑定 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob", "group1").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立即执行,且每隔两秒钟执行一次直到永远 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "group1").startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); //创建scheduler实例 SchedulerFactory sFactory = new StdSchedulerFactory(); Scheduler scheduler = sFactory.getScheduler(); scheduler.start(); //打印当前时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("打印当前时间:"+sf.format(startTime)); scheduler.scheduleJob(jobDetail,trigger); } }
3.浅谈JobExecutionContext&JobDataMap
当Schedule调用一个Job,就会将JobExecutionContext传递给Job的execute方法;Job能通过JobExecutionContext对象访问到Quartz运行时的环境以及Job本身的明细数据。在进行任务调度时,JobDataMap存储在JobExecutionContext中,非常方便获取;JobDataMap可以用来装载任何可序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它;JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法用来存取基本数据类型。获取JobDataMap的两种方式:
- 从Map中直接获取,示例代码如下Job:
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.Job; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.TriggerKey; public class HelloJob implements Job{ @Override public void execute(JobExecutionContext context) throws JobExecutionException { //打印当前执行时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("任务执行时间为:"+sf.format(startTime)); JobKey key = context.getJobDetail().getKey(); System.out.println("My job name and group are:"+key.getName()+":"+key.getGroup()); TriggerKey triggerKey = context.getTrigger().getKey(); System.out.println("My trigger name and group are:"+triggerKey.getName()+":"+triggerKey.getGroup()); JobDataMap jobMap = context.getJobDetail().getJobDataMap(); JobDataMap triggerMap = context.getTrigger().getJobDataMap(); // JobDataMap dataMap = context.getMergedJobDataMap(); //获取合并处理后的参数集合 String jobMsg = jobMap.getString("message"); Float floatValue = jobMap.getFloat("float"); String triggerMsg = triggerMap.getString("triggerMsg"); Double doubleValue = triggerMap.getDouble("double"); System.out.println("My job params are:"+jobMsg+":"+floatValue); System.out.println("My trigger params are:"+triggerMsg+":"+doubleValue); } }
示例代码Schedule:
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; 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; public class HelloScheduler { public static void main(String[] args) throws SchedulerException { // 创建一个JobDetail实例与HelloJob类绑定 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob", "group1"). usingJobData("message", "Hello MyJob1").usingJobData("float", 3.14F).build(); //如果传递参数过程中key相同,则trigger的参数值会覆盖jobdetail里面的参数值 // 创建一个Trigger实例,定义该Job立即执行,且每隔两秒钟执行一次直到永远 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "group1"). usingJobData("triggerMsg", "Hello MyTrigger1").usingJobData("double", 2.0D). startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule(). withIntervalInSeconds(2).repeatForever()).build(); //创建scheduler实例 SchedulerFactory sFactory = new StdSchedulerFactory(); Scheduler scheduler = sFactory.getScheduler(); scheduler.start(); //打印当前时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("打印当前时间:"+sf.format(startTime)); scheduler.scheduleJob(jobDetail,trigger); } }
- Job实现类中添加setter方法对应JobDataMap的键值(Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动地调用这些setter方法),如下代码所示Job:
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.TriggerKey; public class HelloJob implements Job{ private String message; private Float floatValue; private Double doubleValue; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Float getFloatValue() { return floatValue; } public void setFloatValue(Float floatValue) { this.floatValue = floatValue; } public Double getDoubleValue() { return doubleValue; } public void setDoubleValue(Double doubleValue) { this.doubleValue = doubleValue; } @Override public void execute(JobExecutionContext context) throws JobExecutionException { //打印当前执行时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("任务执行时间为:"+sf.format(startTime)); JobKey key = context.getJobDetail().getKey(); System.out.println("My job name and group are:"+key.getName()+":"+key.getGroup()); TriggerKey triggerKey = context.getTrigger().getKey(); System.out.println("My trigger name and group are:"+triggerKey.getName()+":"+triggerKey.getGroup()); System.out.println("Message is:"+message); System.out.println("Float is:"+floatValue); System.out.println("Double is:"+doubleValue); } }
示例代码Schedule:
package com.luna.timer.quarts; import java.text.SimpleDateFormat; import java.util.Date; 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; public class HelloScheduler { public static void main(String[] args) throws SchedulerException { // 创建一个JobDetail实例与HelloJob类绑定 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob", "group1"). usingJobData("message", "Hello MyJob1").usingJobData("floatValue", 3.14F).build(); //如果传递参数过程中key相同,则trigger的参数值会覆盖jobdetail里面的参数值 // 创建一个Trigger实例,定义该Job立即执行,且每隔两秒钟执行一次直到永远 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "group1"). usingJobData("triggerMsg", "Hello MyTrigger1").usingJobData("doubleValue", 2.0D). startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule(). withIntervalInSeconds(2).repeatForever()).build(); //创建scheduler实例 SchedulerFactory sFactory = new StdSchedulerFactory(); Scheduler scheduler = sFactory.getScheduler(); scheduler.start(); //打印当前时间 Date startTime = new Date(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("打印当前时间:"+sf.format(startTime)); scheduler.scheduleJob(jobDetail,trigger); } }