任务调度的 Java 实现方法二:quartz

来源:互联网 发布:java内嵌webkit浏览器 编辑:程序博客网 时间:2024/05/01 04:23

 

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs。 

Quartz框架是一个全功能、开源的任务调度服务,可以集成几乎任何的java应用程序—从小的单片机系统到大型的电子商务系统。Quartz可以执行上千上万的任务调度。

Quartz就是一个纯 Java 实现的作业调度工具,相当于数据库中的 Job、Windows 的计划任务、Unix/Linux 下的 Cron,但 Quartz 可以把排程控制的更精细.

Quartz核心的概念scheduler任务调度、Job任务、Trigger触发器、JobDetail任务细节

Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器、任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述 
Quartz 调度包的两个基本单元是作业和触发器。作业是能够调度的可执行任务,触发器提供了对作业的调度
调度器:调度器用于将与作业触发器关联,一个作业可关联多个触发器,这样每个触发器被可以触发的作业执行;一个触发器可用于控制多个作业,触发触发时, 全部作业将获得调度。Quartz的调度器由Scheduler接口体现. 
作业只需实现org.quartz.job接口即可.Job接口包含一个方法 execute(),execute方法体是被调度的作业体。一旦实现Job接口和execute()方法, 
Quartz确定作业运作的时候,它将调用 execute()方法体。 
触发器有SimpleTrigger和CronTrigger两种类型 

Job:是一个接口只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中 

Quartz是一个完全由java编写的开源作业调度框架。该框架主要包含三个主要组件:Job、Trigger、Scheduler;
Job:作业类,也就是要定期执行的业务逻辑类,需要实现Job接口以及其中的execute 方法。主要有两种类型的 job:无状态的(stateless)和有状态的(stateful)。对于同一个 trigger 来说,有状态的 job 不能被并行执行,只有上一次触发的任务被执行完之后,才能触发下一次执行。
注意:1.Job类必须有默认的无参构造方法,当然不覆盖的话类本身就是无参的构造方法 
2.Job的scope必须是Public类型的,因为quartz根据反射机制实例化类,如果不是public的,无法对其暴露
3.Job类不能是内部类,原因同上,所以最好单独建类  

JobDetail:任务细节,Quartz执行Job时,需要新建个Job实例,但是不能直接操作Job类,所以通过JobDetail来获取Job的名称、描述信息。

Trigger:触发器,用来定义什么时候执行作业类。它有很多实现,最常用的是 SimpleTrigger(从startTime时间点开始,每隔repeatInterval时间间隔,执行job一次,共执行repeatCount次)和CronTrigger(根据用户指定的Cron表达式来定时执行作业类,比如每月最后一日的10:15触发一次事件等),一般情况使用SimpleTrigger,和CronTrigger,这个触发器实现了Trigger接口。

Scheduler:调度器,用来启动整个作业调度框架。需要把JobDetail和Trigger注册到scheduler中,才可以执行。
Scheduler 负责管理 Trigger 、调度 Job , SchedulerFactory 则是 Scheduler 工厂,负责生成 Scheduler 。

Quartz三个核心组件相对应有三种监听器:JobListener、TriggerListener和SchedulerListener。 
1.JobListener 
jobToBeExecuted:Job执行之前调用该方法,有一个JobExecutionContext参数,可以通 过该参数获得Job的执行信息,如本次执行时间以及下次执行时间等。 
jobWasExecuted:Job执行之后调用该方法。 
2.TriggerListener  
triggerFired:Trigger执行之前调用该方法。 triggerComplete:Trigger执行之后调用该方法。 
3.SchedulerListener  
可以在Scheduler启动、关闭等事件中调用该接口的方法。
不同的版本的jar包,具体的操作不太相同,但是思路是相同的;
比如1.8.6jar包中,JobDetail是个类,直接通过构造方法与Job类关联。SimpleTrigger和CornTrigger是类;
在2.0.2jar包中,JobDetail是个接口,SimpleTrigger和CornTrigger是接口
1.8.6jar包: 

public class MyJob implements Job {@Override//把要执行的操作,写在execute方法中public void execute(JobExecutionContext arg0) throws JobExecutionException {System.out.println("测试Quartz"+new Date());}}public static void main(String[] args) {//通过schedulerFactory获取一个调度器SchedulerFactory schedulerfactory=new StdSchedulerFactory();Scheduler scheduler=null;try{//通过schedulerFactory获取一个调度器scheduler=schedulerfactory.getScheduler();   //创建jobDetail实例,绑定Job实现类, 指明job的名称,所在组的名称,以及绑定job类JobDetail jobDetail=new JobDetail("job1", "jgroup1", MyJob.class);   //定义调度触发规则,比如每1秒运行一次,共运行8次SimpleTrigger simpleTrigger=new SimpleTrigger("simpleTrigger","triggerGroup");//马上启动simpleTrigger.setStartTime(new Date());//间隔时间simpleTrigger.setRepeatInterval(1000);//运行次数simpleTrigger.setRepeatCount(8);   //把作业和触发器注册到任务调度中scheduler.scheduleJob(jobDetail, simpleTrigger);   //启动调度scheduler.start();      }catch(SchedulerException e){e.printStackTrace();}}public static void main(String[] args) {//通过schedulerFactory获取一个调度器SchedulerFactory schedulerfactory=new StdSchedulerFactory();Scheduler scheduler=null;try{//通过schedulerFactory获取一个调度器scheduler=schedulerfactory.getScheduler();   //创建jobDetail实例,绑定Job实现类,指明job的名称,所在组的名称,以及绑定job类JobDetail jobDetail=new JobDetail("job1", "jgroup1", MyJob.class);   //定义调度触发规则,每天上午10:15执行CronTrigger cornTrigger=new CronTrigger("cronTrigger","triggerGroup");//执行规则表达式cornTrigger.setCronExpression("0 15 10 * * ? *");//把作业和触发器注册到任务调度中scheduler.scheduleJob(jobDetail, cornTrigger);   //启动调度scheduler.start();      }catch(Exception e){e.printStackTrace();}   }

对于2.0.2jar包如下(其中的job类不变):
public static void main(String[] args) {   //通过schedulerFactory获取一个调度器SchedulerFactory schedulerfactory=new StdSchedulerFactory();Scheduler scheduler=null;   try{//通过schedulerFactory获取一个调度器scheduler=schedulerfactory.getScheduler();   //创建jobDetail实例,绑定Job实现类,指明job的名称,所在组的名称,以及绑定job类JobDetail job=JobBuilder.newJob(MyJob.class).withIdentity("job1", "jgroup1").build();    //定义调度触发规则 //使用simpleTrigger规则//Trigger trigger=TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup")        .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withRepeatCount(8))        .startNow().build();//使用cornTrigger规则  每天10点42分Trigger trigger=TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup")          .withSchedule(CronScheduleBuilder.cronSchedule("0 42 10 * * ? *"))          .startNow().build();    //把作业和触发器注册到任务调度中scheduler.scheduleJob(job, trigger);   //启动调度scheduler.start();         }catch(Exception e){   e.printStackTrace();   }   }

CronExpression配置说明 
格式: [秒] [分] [小时] [日] [月] [周] [年]
序号说明是否必填允许填写的值允许的通配符1秒是0-59, - * /2分是0-59, - * /3小时是0-23, - * /4日是1-31, - * ? / L W5月是1-12 or JAN-DEC, - * /6周是1-7 or SUN-SAT, - * ? / L #7年否empty 或 1970-2099, - * /

通配符说明:
表示所有值. 例如:在分的字段上设置 "*",表示每一分钟都会触发。
表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为"?" 具体设置为 0 0 0 10 * ?
表示区间。例如 在小时上设置 "10-12",表示 10,11,12点都会触发。
表示指定多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发
/ 用于递增触发。如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)。在月字段上设置'1/3'所示每月1号开始,每隔三天触发一次。
L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于"7"或"SAT"。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示“本月最后一个星期五"
W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-").
小提示:'L'和 'W'可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资 ) 
序号(表示每月的第几个周几),例如在周字段上设置"6#3"表示在每月的第三个周六.注意如果指定"#5",正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了)
小提示:周字段的设置,若使用英文字母是不区分大小写的 MON 与mon相同

L("last")    ("last") "L" 用在day-of-month字段意思是 "这个月最后一天";用在 day-of-week字段, 它简单意思是 "7" or "SAT"。 如果在day-of-week字段里和数字联合使用,它的意思就是 "这个月的最后一个星期几" – 例如: "6L" means "这个月的最后一个星期五". 当我们用“L”时,不指明一个列表值或者范围是很重要的,不然的话,我们会得到一些意想不到的结果。    
W("weekday")    只能用在day-of-month字段。用来描叙最接近指定天的工作日(周一到周五)。例如:在day-of-month字段用“15W”指“最接近这个月第15天的工作日”,即如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发;如果这个月第15天是周日,那么触发器将会在这个月第16天即周一触发;如果这个月第15天是周二,那么就在触发器这天触发。注意一点:这个用法只会在当前月计算值,不会越过当前月。“W”字符仅能在day-of-month指明一天,不能是一个范围或列表。也可以用“LW”来指定这个月的最后一个工作日。   
#    只能用在day-of-week字段。用来指定这个月的第几个周几。例:在day-of-week字段用"6#3"指这个月第3个周五(6指周五,3指第3个)。如果指定的日期不存在,触发器就不会触发。     
C    指和calendar联系后计算过的值。例:在day-of-month 字段用“5C”指在这个月第5天或之后包括calendar的第一天;在day-of-week字段用“1C”指在这周日或之后包括calendar的第一天 

0 0 12 * * ?每天12点触发0 15 10 ? * *每天10点15分触发0 15 10 * * ?每天10点15分触发0 15 10 * * ? *每天10点15分触发0 15 10 * * ? 20052005年每天10点15分触发0 * 14 * * ?每天下午的 2点到2点59分每分触发0 0/5 14 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发)0 0/5 14,18 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发) 每天下午的 18点到18点59分(整点开始,每隔5分触发)0 0-5 14 * * ?每天下午的 2点到2点05分每分触发0 10,44 14 ? 3 WED3月分每周三下午的 2点10分和2点44分触发0 15 10 ? * MON-FRI从周一到周五每天上午的10点15分触发0 15 10 15 * ?每月15号上午10点15分触发0 15 10 L * ?每月最后一天的10点15分触发0 15 10 ? * 6L每月最后一周的星期五的10点15分触发0 15 10 ? * 6L 2002-2005从2002年到2005年每月最后一周的星期五的10点15分触发0 15 10 ? * 6#3每月的第三周的星期五开始触发0 0 12 1/5 * ?每月的第一个中午开始每隔5天触发一次0 11 11 11 11 ?每年的11月11号 11点11分触发(光棍节)

  

 

0 0