Quart 学习

1.关键接口

  • Scheduler,任务调度的API;它可以用来启动或者终止任务等。
  • Job,具体的任务接口;通过实现它,来让任务调度执行具体的任务。
  • JobDetail ,用来定义Job的实例。
  • Trigger ,触发器用来定义给定的Job应该如何执行。
  • JobBuilder ,用来定义/构建Jobdetail实例。
  • TriggerBuilder ,用来定义/构建Trigger实例。

2.简单例子

下面是一个简单的例子,创建一个简单的任务调度。 
创建一个Job,名为HelloQuartzJob:

public class HelloQuartzJob implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Hello, Quartz! "+
                formatter.format(new Date()) + " by " + context.getTrigger());
    }
}

实现Job接口中的execute方法,这个方法中是我们需要任务调度执行的具体内容。

然后我们就可以编写一个测试类,来执行Job。

public class HelloQuartzScheduling {
    public static void main(String[] args) throws SchedulerException {

        //创建JobDetail
        JobDetail jobDetail = JobBuilder.newJob(HelloQuartzJob.class)
                .withIdentity("hello","group1")
                .build();

        //创建Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger","group1")
                .startNow()
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                //每5s运行一次
                                .withIntervalInSeconds(5)
                                //重复运行3次
                                .withRepeatCount(3)
                ).build();

        //获取Scheduler,并启动任务
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        //添加job,以及其关联的trigger
        scheduler.scheduleJob(jobDetail, trigger);
        //启动job
        scheduler.start();
    }
}

  运行结果,如下:

Jobs与JobDetails

正如第一篇文章看到的那样,实现一个Job是非常简单的,只需要完成execute()方法就行了。 
那么Jobs与JobDetails有什么关系呢?简而言之,Job是对任务的一个具体实现;谁执行了这个任务呢?这就需要JobDetail来实现,所以JobDetail就是Job的一个具体实例;如9点上语文课是一个具体任务,而刘老师在9点上语文课就是这个任务的一个具体实例。 
Scheduler执行Job时,在调用execute()方法前会先实例化Job;一旦执行结束,该实例就会被丢弃,然后被垃圾回收。 
需要注意的是Job必须有一个无参的构造器;另外在Job类中定义数据属性是没有意义的,因为这些属性值并不会在执行期间保存。

JobDataMap

上面说到Job中无法定义属性来传递数据,那么如果我们需要传递数据该怎么做?就是使用JobDataMap,它是JobDetail的一个属性。JobDataMap是Map接口的一个实现,并且它有一些便利的方法来储存和检索基本类型数据。 
修改之前的测试类如下:

//创建JobDetailJobDetail jobDetail = JobBuilder.newJob(HelloQuartzJob.class)        .withIdentity("hello","group1")        .usingJobData("name", "sky")        .build();

  添加一个值为sky的name属性。然后在HelloQuartzJob中,我们就可以获取到该属性:

public class HelloQuartzJob implements Job {
    public HelloQuartzJob() {
        System.out.println("Hello, Quartz! ----------------------");
    }

    public void execute(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //使用JobDataMap
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        String name = jobDataMap.getString("name");

        System.out.println("Hello, " + name + " " +
                formatter.format(new Date()) + " by " + context.getTrigger());
    }
}

  然后运行测试类:

如果在Job类中定义与JobDataMap中键值一致的set和get方法,那么Quartz会自动将这些属性注入。如:

public class HelloQuartzJob implements Job {
    String name;

    public HelloQuartzJob() {
        System.out.println("Hello, Quartz! ----------------------");
    }

    public void execute(JobExecutionContext context) throws JobExecutionException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        //使用JobDataMap
//        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
//        String name = jobDataMap.getString("name");

        System.out.println("Hello, " + name + " " +
                formatter.format(new Date()) + " by " + context.getTrigger());
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

另外Trigger中也可以设置JobDataMap属性,这是为了在多个Trigger中使用相同的Job。JobExecutionContext 将会合并JobDetail与Trigger的JobDataMap,如果其中属性名相同,后者将覆盖前者。可以使用context.getMergedJobDataMap()方法来获取合并后的JobDataMap。

Job的状态与并发

@DisallowConcurrentExecution,如果使用该注解,那么同一时间将只有一个Job实例被执行。如,ReportJob有个实例为ReportForJoe,那么同一时间只有一个ReportForJoe被执行。而ReportForMike等都可以执行。 
@PersistJobDataAfterExecution,如果使用该注解,在Job被执行结束后,将会更新JobDataMap,这样下次Job执行后就会使用新的值而不是初始值。 
如果使用@PersistJobDataAfterExecution注解,推荐也使用@DisallowConcurrentExecution注解,这是为了避免并发问题导致数据紊乱。

其它属性

  • Durability,持久性;如果Job是非持久性的,一旦没有Trigger与其相关联,它就会从Scheduler中被删除。也就是说Job的生命周期和其Trigger是关联的。
  • RequestsRecovery,如果为true,那么在Scheduler异常中止或者系统异常关闭后,当Scheduler重启后,Job会被重新执行。

JobExecutionException

execute()方法只允许抛出JobExecutionException异常

Job与JobDetail是Quartz用来定义具体任务的,而Trigger则是用来定义任务如何执行的。Quartz提供了Trigger接口来定义公共属性,使用TriggerBuilder可以创建具体类型的Trigger;最常见的两种Trigger分别是SimpleTrigger、CronTrigger。

Trigger的公共属性:

    • key,该属性是为了标识Trigger的。
    • startTime,Trigger第一次被Scheduler触发的时间;该属性的值是指定某个时间点的java.util.Date对象。
    • endTime,Trigger不再被执行的时间。
    • priority,优先级;通过设置优先级属性可以控制Trigger被执行的顺序,该属性默认值是5,可以为正整数也可以为负整数。需要注意的是,只有在触发时间相同时,优先级属性才会有效;比如10:59执行的任务总是会在11:00执行的任务之前执行;另外,如果Trigger是可恢复的,那么恢复后,优先级是不会改变的。
    • misfire,如果因为某些原因,错过触发时间,就需要使用该属性来调整。不同类型的Trigger拥有不同的misfire,但是默认的是smart policy,这种情况下会根据Trigger的类型与配置来动态的调整行为。
    • Calendars,该属性并不是java.util.Calendar类型,它的作用是排除某些时间,比如在周末不执行任务。Quratz的Calendar对象是一个实现了Calendar接口的序列化对象,Calendars接口如下:
package org.quartz;
public interface Calendar {
  public boolean isTimeIncluded(long timeStamp);
  public long getNextIncludedTime(long timeStamp);
}

  这两个方法都是精确到毫秒的;如果只是排除以天为单位的时间,可以使用HolidayCalendar。 
Calendars必须实例化,然后通过Scheduler的addCalendar()方法注册。Calendars可以重复使用,如下代码:

Trigger trigger1 = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "test")
                .startAt(DateBuilder.futureDate(3, IntervalUnit.SECOND))
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInMilliseconds(5000)
                        .withIntervalInSeconds(5)
                        .withRepeatCount(5))
                .modifiedByCalendar("holidayCalendar")
                .build();

        Trigger trigger2 = TriggerBuilder.newTrigger()
                .withIdentity("trigger2", "test")
                .startAt(DateBuilder.futureDate(3, IntervalUnit.SECOND))
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInMilliseconds(5000)
                        .withIntervalInSeconds(5)
                        .withRepeatCount(5))
                .modifiedByCalendar("holidayCalendar")
                .build();

  

SimpleTrigger

下面来看SimpleTrigger。通过之前的例子可以看到如何创建Trigger,首先通过TriggerBuilder.newTrigger()方法建立一个TriggerBuilder对象,然后通过withSchedule()方法指定了SimpleScheduleBuilder,最后build()方法构建出了SimpleTrigger对象。 
SimpleTrigger很简单,之前例子中创建的都是SimpleTrigger,任务启动后每隔5s运行一次,总共运行5次。Quartz提供了DateBuilder工具类来方便设置时间,里面提供了很多方法,如上面Trigger2设置的启动时间就是3秒后启动任务。

CronTrigger

CronTrigger使用cron表达式来设置触发时间。CronTrigger创建方式:

Trigger trigger3 = TriggerBuilder.newTrigger()
                .withIdentity("cron trigger", "test")
                .withSchedule(
                    //每5秒执行一次
                    CronScheduleBuilder.cronSchedule("0/5 * * ? * *")
                ).build();

cron表达式

cron表达式的格式为:秒 分 时 日 周 年;其中年是可选的,其它为必填。

附:cronExpression配置说明

字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * /

表达式 意义
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午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" 每月的第三个星期五上午10:15触发

特殊字符 意义
* 表示所有值;
? 表示未说明的值,即不关心它为何值;
- 表示一个指定的范围;
, 表示附加一个可能值;
/ 符号前表示开始时间,符号后表示每次递增的值;
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的第一天

下图为每个属性允许使用的符号:

转:http://blog.csdn.net/a4307515

时间: 2024-11-05 06:24:16

Quart 学习的相关文章

Quartz定时任务学习(二)web应用/Quartz定时任务学习(三)属性文件和jar

web中使用Quartz 1.首先在web.xml文件中加入 如下内容(根据自己情况设定) 在web.xml中添加QuartzInitializerServlet,Quartz为能够在web应用中使用,提供了一个QuartzInitializerServlet和一个QuartzInitializerListener,用于在加载web应用时,对quartz进行初始化. <servlet> <servlet-name> QuartzInitializer </servlet-na

大熊君学习html5系列之------requestAnimationFrame(实现动画的另一种方案)

一,开篇分析 Hi,大家好!大熊君又和大家见面了,(*^__^*) 嘻嘻……,这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例, 让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美驾驭O(∩_∩)O~,好了,废话不多说,直接进入今天的主题, 今天主要讲的是“requestAnimationFrame API”及在客户端浏览器中的作用,并且会引入一个实际的例子做为讲解的原型范例,让我们先来看看“request

Vue.js学习笔记:属性绑定 v-bind

v-bind  主要用于属性绑定,Vue官方提供了一个简写方式 :bind,例如: <!-- 完整语法 --> <a v-bind:href="url"></a> <!-- 缩写 --> <a :href="url"></a> 绑定HTML Class 一.对象语法: 我们可以给v-bind:class 一个对象,以动态地切换class.注意:v-bind:class指令可以与普通的class特

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

微信小程序学习总结(2)------- 之for循环,绑定点击事件

最近公司有小程序的项目,本人有幸参与其中,一个项目做下来感觉受益匪浅,与大家做下分享,欢迎沟通交流互相学习. 先说一下此次项目本人体会较深的几个关键点:微信地图.用户静默授权.用户弹窗授权.微信充值等等. 言归正传,今天分享我遇到的关于wx:for循环绑定数据的一个tips:  1. 想必大家的都知道wx:for,如下就不用我啰嗦了: <view class="myNew" wx:for="{{list}}">{{item.title}}<view

【安全牛学习笔记】

弱点扫描 ╋━━━━━━━━━━━━━━━━━━━━╋ ┃发现弱点                                ┃ ┃发现漏洞                                ┃ ┃  基于端口五福扫描结果版本信息(速度慢)┃ ┃  搜索已公开的漏洞数据库(数量大)      ┃ ┃  使用弱点扫描器实现漏洞管理            ┃ ╋━━━━━━━━━━━━━━━━━━━━╋ [email protected]:~# searchsploit Usage:

winform学习日志(二十三)---------------socket(TCP)发送文件

一:由于在上一个随笔的基础之上拓展的所以直接上代码,客户端: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using Sys

零基础的人该怎么学习JAVA

对于JAVA有所兴趣但又是零基础的人,该如何学习JAVA呢?对于想要学习开发技术的学子来说找到一个合适自己的培训机构是非常难的事情,在选择的过程中总是 因为这样或那样的问题让你犹豫不决,阻碍你前进的步伐,今天就让小编为您推荐培训机构新起之秀--乐橙谷Java培训机构,助力你成就好未来. 选择java培训就到乐橙谷 北京有什么好的Java培训机构?来乐橙谷北京学Java,零基础走起,乐橙谷Java基础班授课老师经验非常丰富,课程内容安排合理,适合于有一点点Java基础甚至一点都不会Java的同学学

最全解析如何正确学习JavaScript指南,必看!

划重点 鉴于时不时,有同学私信问我:怎么学前端的问题.这里统一回复一下,如下次再遇到问我此问题同学,就直接把本文链接地址发给你了. "前端怎么学"应该因人而异,别人的方法未必适合自己.就说说我的学习方法吧:我把大部分时间放在学习js上了.因为这个js的学习曲线,先平后陡.项目实践和练习啥的,我不说了,主要说下工作之外的时间利用问题.我是怎么学的呢,看书,分析源码.个人这几天统计了一下,前端书籍目前看了50多本吧,大部分都是js的.市面上的书基本,差不多都看过. 第一个问题:看书有啥好处