最近使用到Quartz框架来作定时推送数据的功能的调度(注:在Java可使用java.util.Timer和实现java.util.TimerTask接口的类作定时任务功能)。html
本文主要从大的框架方面介绍Quartz的基本使用和Quartz对用户提供的扩展点JobListener等监听接口。java
一般对于做业调度咱们关注这三个方面的内容:做业,调度时间,由谁调度。好比:我明天去北京。这就好中,将“去北京”看作一个做业,“我”就是这个做业的调度者,而“明天”天然就是调度的时间(也能够看做是去北京这个做业的触发时间)。spring
由上面的小情节能够看出框架能为咱们作那些事呢?分离通用的,业务无关的部分组织成为解决某一问题或特定问题的模版代码即为框架。正好,Quartz就是做业调度方面或者领域的解决方案框架。再去看“去北京”这个关键词,能够发现去北京对于实际的业务而言仅仅是一个描述性的语句,而怎么去(灰机,BBC,仍是绿皮车)好像这些并没能体现出来,而这样没有体现出来的好处就是框架和业务实现彻底解耦。这里就要引入几个做业调度方面的专业名词,好比Job,Trigger ,Scheduler。咱们这一这么组织这三个名词,好比:一个Schedule怀揣个Trigger,这个Trigger有个玩叫Job,时不时拿出来玩两下。至于玩一下Job,Job可以产生怎样的影响对于Trigger而言并不关心,不过这里彷佛使得Job与Trigger产生了耦合,由于Job属于具体业务。对于一个完备的做业调度解决方案Quartz而言这样的问题已不是问题,Quartz用JobDetail来表示Job或者表达Job,从而让具备具体业务的Job与整个框架分离。编程
下面经过Quartz的类图来宏观的介绍Quartz2.x的使用。
框架
1.Job和JobDetail分布式
具体做业业务实现Job接口,具体在做业调度中使用JobDetail,使用JobBuilder构造器来构造具体的JobDetail。两个接口+一个构造者模式的JobDetail构造器完成了具体业务Job和实际做业调度中的JobDetail分离。实际应用中只要面向JobDetail和Job两个接口编程,隐藏了具体的实现如:JobDetailImpl类。ide
2.Triiger(做业触发器)ui
对于做业触发器大多与时间,日期,调度次数,间隔时间,调度延时等有关,Quartz对做业触发作了分类并提供了TriggerBuilder。this
从上图能够看到Trigger接口下有不一样的触发类型,如平常间隔触发(DailyTimeIntervalTriggerImpl),基于日历的触发,Cron出发,简单的触发。一样TriggerBuilder提供了构建Trigger的简便方式,使用者能够经过其来设置不一样的属性信息构建具体的Trigger实现的实例。spa
3.做业调度器Scheduler
Quartz提供了不一样类型的调度器实现,通常咱们使用StdScheduler便可知足须要,如涉及到分布式或者远程方法调用则能够选择其它两种合适的实现。
4.Quartz提供的扩展之Listener
Quartz提供了各类Listener接口为用户观察做业,触发器,做业调度器执行过程提供了扩展点。
Scheduler对象具备ListenerManager的属性,ListenerManager对象用来管理TriggerListener,JobListener,SchedulerListener的实现,监听关系(好比:指定全局Job监听,指定特定的Job监听等),具体使用参见下文。
下面提供一组Quartz使用的示例代码:
package secondriver.springsubway.demo.job; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import org.quartz.impl.matchers.GroupMatcher; public class TestJobListener { public static Scheduler scheduler; @BeforeClass public static void setBeforeClass() throws SchedulerException { StdSchedulerFactory schedulerFactory = new StdSchedulerFactory(); scheduler = schedulerFactory.getScheduler(); scheduler.start(); } @AfterClass public static void setAfterClass() throws SchedulerException { if (scheduler.isStarted()) { scheduler.shutdown(true); } } //Prepared for Test /** * 使用Builder模式构建JobDetail实例 * @return */ public static JobDetail getJobDetail() { return JobBuilder.newJob(MyJob.class).withDescription("MyJobDetail") .withIdentity("myJob", "myJobGroup") .build(); } /** * 使用Builder模式构建Trigger实例 * @return */ public static Trigger getTrigger() { return TriggerBuilder.newTrigger().withDescription("MyTrigger").withIdentity("myTrigger", "myTriggerGroup") .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3)) .startNow().build(); } @Test public void testOne() throws SchedulerException { JobDetail jobDetail = getJobDetail(); Trigger trigger = getTrigger(); scheduler.getListenerManager().addJobListener(new MyJobListener()); scheduler.getListenerManager().addTriggerListener(new MyTriggerListener()); scheduler.scheduleJob(jobDetail, trigger); } @Test public void testTwo() throws SchedulerException { JobDetail jobDetail = getJobDetail(); Trigger trigger = getTrigger(); /** * 为指定jobGrup添加JobListener */ scheduler.getListenerManager().addJobListener(new MyJobListener(), GroupMatcher.jobGroupEquals("myJobGroup")); /** * 为指定triggerGroup添加TriggerListener */ scheduler.getListenerManager().addTriggerListener(new MyTriggerListener(), GroupMatcher.triggerGroupEquals ("myTriggerGroup")); scheduler.scheduleJob(jobDetail, trigger); } @Test public void testThree() throws SchedulerException, InterruptedException { JobDetail jobDetail = getJobDetail(); //非持久化Job无关联Trigger添加到Scheduler须要使用addJob第三个参数storeNonDurableWhileAwaitingScheduling为true scheduler.addJob(jobDetail, false, true); //JobDetail 1<->* Trigger Trigger trigger1 = TriggerBuilder.newTrigger().forJob(jobDetail) .startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build(); Trigger trigger2 = TriggerBuilder.newTrigger().forJob(jobDetail) .startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build(); scheduler.scheduleJob(trigger1); scheduler.scheduleJob(trigger2); Thread.sleep(10000); } /** * 具体业务实现类,实现Job接口的execute方法便可 */ public static class MyJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("MyJob " + this.getClass().getCanonicalName()); } } /** * JobListener实现 * <p/> * JobListener方法执行顺序 * <p/> * 若是TriigerListener的vetoJobExecution返回true * triggerFired -> vetoJobExecution ->jobExecutionVetoed * <p/> * 若是TiggerListener的vetoJobExecution返回false * triggerFired -> vetoJobExecution ->jobToBeExecuted -> [Job execute] -> jobWasExecuted * ->[triggerMisfired|triggerComplete] */ public static class MyJobListener implements JobListener { @Override public String getName() { return "MyJobListener"; } @Override public void jobToBeExecuted(JobExecutionContext context) { System.out.println("jobToBeExecuted:" + context.getJobDetail().getDescription()); } @Override public void jobExecutionVetoed(JobExecutionContext context) { System.out.println("jobExecutionVetoed:" + context.getJobDetail().getDescription()); } @Override public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) { System.out.println("jobWasExecuted:" + context.getJobDetail().getDescription()); } } /** * TriggerListener实现 */ public static class MyTriggerListener implements TriggerListener { @Override public String getName() { return "MyTriggerListener"; } @Override public void triggerFired(Trigger trigger, JobExecutionContext context) { System.out.println("triggerFired:" + trigger.getDescription()); } @Override public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) { System.out.println("vetoJobExecution:" + trigger.getDescription()); return false; /** return:false triggerFired:MyTrigger vetoJobExecution:MyTrigger jobToBeExecuted:MyJobDetail MyJob secondriver.quartz.TestJobListener.MyJob jobWasExecuted:MyJobDetail triggerComplete:MyTrigger */ /** return:true triggerFired:MyTrigger vetoJobExecution:MyTrigger jobExecutionVetoed:MyJobDetail */ } @Override public void triggerMisfired(Trigger trigger) { System.out.println("triggerMisfired:" + trigger.getDescription()); } @Override public void triggerComplete(Trigger trigger, JobExecutionContext context, Trigger.CompletedExecutionInstruction triggerInstructionCode) { System.out.println("triggerComplete:" + trigger.getDescription()); } } }
上述代码依赖Quartz框架的Maven配置:
<dependency> <groupId>org.quartz-scheduler</groupId> <version>2.2.1</version> <artifactId>quartz</artifactId> </dependency>
Quartz在Java应用做业调度方面提供了很是完备的实现,本文经过三个做业调度方面的关键词和Quartz的用户扩展Listener简要介绍了Quartz的使用,更多内容能够查看Quartz用户手册或者源代码。