Demo

SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();

  Scheduler sched = schedFact.getScheduler();

  sched.start();

  // define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("myJob", "group1")// name, group
.build(); // Trigger the job to run now, and then every 40 seconds
Trigger trigger = newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(40)
.repeatForever())
.build(); // Tell quartz to schedule the job using our trigger
sched.scheduleJob(job, trigger);

看以看到,一个Quatz分为三个部分,分别是Scheduler, Job, Trigger,后面会讲为什么trigger和job要分开。

Once a scheduler is instantiated, it can be started, placed in stand-by mode, and shutdown. Note that once a scheduler is shutdown, it cannot be restarted without being re-instaniated. Triggers do not fire(jobs do not execute) until the scheduler has been started, nor while it is in the paused state.

Jobs and Triggers

A Job is a class that implement the Job interface, which has only one simple method.

void execute(JobExecutionContext context)

When the Job’s trigger fires (more on that in a moment), the execute(..) method is invoked by one of the scheduler’s worker threads. The JobExecutionContext object that is passed to this method provides the job instance with information about its “run-time” environment - a handle to the Scheduler that executed it, a handle to the Trigger that triggered the execution, the job’s JobDetail object, and a few other items.

The JobDetail object is created by the Quartz client (your program) at the time the Job is added to the scheduler. It contains various property settings for the Job, as well as a JobDataMap, which can be used to store state information for a given instance of your job class. It is essentially the definition of the job instance, and is discussed in further detail in the next lesson.

Trigger objects are used to trigger the execution (or ‘firing’) of jobs. When you wish to schedule a job, you instantiate a trigger and ‘tune’ its properties to provide the scheduling you wish to have. Triggers may also have a JobDataMap associated with them - this is useful to passing parameters to a Job that are specific to the firings of the trigger. Quartz ships with a handful of different trigger types, but the most commonly used types are SimpleTrigger and CronTrigger.

SimpleTrigger is handy if you need ‘one-shot’ execution (just single execution of a job at a given moment in time), or if you need to fire a job at a given time, and have it repeat N times, with a delay of T between executions. CronTrigger is useful if you wish to have triggering based on calendar-like schedules - such as “every Friday, at noon” or “at 10:15 on the 10th day of every month.”

Why Jobs AND Triggers? Many job schedulers do not have separate notions of jobs and triggers. Some define a ‘job’ as simply an execution time (or schedule) along with some small job identifier. Others are much like the union of Quartz’s job and trigger objects. While developing Quartz, we decided that it made sense to create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits.

For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job. Another benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired, so that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define its associated job.

More About Jobs and Job Details

Now consider the job class "HelloJob" defined as such:

public class HelloJob implements Job {

    public HelloJob() {
} public void execute(JobExecutionContext context)
throws JobExecutionException
{
System.err.println("Hello! HelloJob is executing.");
}
}

Notice that we give the scheduler a JobDetail instance, and that it knows the type of job to be executed by simply providing the job's class as we build the JobDetail.

Each (and every) time the scheduler executes the job, it creates a new instance of the class before calling its execute(..) method. When the execution is complete, references to the job class instance are dropped, and the instance is then garbage collected. One of the ramifications of this behavior is the fact that jobs must have a no-argument constructor (when using the default JobFactory implementation). Another ramification is that it does not make sense to have state data-fields defined on the job class - as their values would not be preserved between job executions.

You may now be wanting to ask "how can I provide properties/configuration for a Job instance?" and "how can I keep track of a job's state between executions?" The answer to these questions are the same: the key is the JobDataMap, which is part of the JobDetail object.

JobDataMap

The JobDataMap can be used to hold any amount of (serializable) data objects which you wish to have made available to the job instance when it executes. JobDataMap is an implementation of the Java Map interface, and has some added convenience methods for storing and retrieving data of primitive types.

 // define the job and tie it to our DumbJob class
JobDetail job = newJob(DumbJob.class)
.withIdentity("myJob", "group1") // name "myJob", group "group1"
.usingJobData("jobSays", "Hello World!")
.usingJobData("myFloatValue", 3.141f)
.build();

Here's a quick example of getting data from the JobDataMap during the job's execution:

不太理解JobKey是干嘛用的

public class DumbJob implements Job {

    public DumbJob() {
} public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey(); JobDataMap dataMap = context.getJobDetail().getJobDataMap(); String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue"); System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}

Be awared of the serialization problem when using self-defined type.

If you add setter methods to your job class that correspond to the names of keys in the JobDataMap (such as asetJobSays(String val) method for the data in the example above), then Quartz's default JobFactory implementation will automatically call those setters when the job is instantiated, thus preventing the need to explicitly get the values out of the map within your execute method.

Triggers can also have JobDataMaps associated with them. This can be useful in the case where you have a Job that is stored in the scheduler for regular/repeated use by multiple Triggers, yet with each independent triggering, you want to supply the Job with different data inputs.

每一个trigger还能携带数据信息,为自己的job instance提供数据。

The JobDataMap that is found on the JobExecutionContext during Job execution serves as a convenience. It is a merge of the JobDataMap found on the JobDetail and the one found on the Trigger, with the values in the latter overriding any same-named values in the former.

Here's a quick example of getting data from the JobExecutionContext's merged JobDataMap during the job's execution:

下面是提供set后的例子

public class DumbJob implements Job {

    String jobSays;
float myFloatValue;
ArrayList state; public DumbJob() {
} public void execute(JobExecutionContext context)
throws JobExecutionException
{
JobKey key = context.getJobDetail().getKey(); JobDataMap dataMap = context.getMergedJobDataMap(); // Note the difference from the previous example state.add(new Date()); System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
} public void setJobSays(String jobSays) {
this.jobSays = jobSays;
} public void setMyFloatValue(float myFloatValue) {
myFloatValue = myFloatValue;
} public void setState(ArrayList state) {
state = state;
} }

是否需要加set函数取决于自己的喜好,它们本身也是各有利弊,没有哪个完全优越。

一个job可能取多个名字,取决于提供给他的参数,可能有个叫做“jobForA", "JobForB"

Lesson 4: More About Triggers

SimpleTrigger should meet your scheduling needs if you need to have a job execute exactly once at a specific moment in time, or at a specific moment in time followed by repeats at a specific interval. For example, if you want the trigger to fire at exactly 11:23:54 AM on January 13, 2015, or if you want it to fire at that time, and then fire five more times, every ten seconds.

Build a trigger for a specific moment in time, with no repeats:

SimpleTrigger trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger1", "group1")
.startAt(myStartTime) // some Date
.forJob("job1", "group1") // identify job with name, group strings
.build();

Build a trigger for a specific moment in time, then repeating every ten seconds ten times:

  trigger = newTrigger()
.withIdentity("trigger3", "group1")
.startAt(myTimeToStartFiring) // if a start time is not given (if this line were omitted), "now" is implied
.withSchedule(simpleSchedule()
.withIntervalInSeconds(10)
.withRepeatCount(10)) // note that 10 repeats will give a total of 11 firings
.forJob(myJob) // identify job with handle to its JobDetail itself
.build();

Build a trigger that will fire once, five minutes in the future:

 trigger = (SimpleTrigger) newTrigger()
.withIdentity("trigger5", "group1")
.startAt(futureDate(5, IntervalUnit.MINUTE)) // use DateBuilder to create a date in the future
.forJob(myJobKey) // identify job with its JobKey
.build();

Build a trigger that will fire now, then repeat every five minutes, until the hour 22:00:

 trigger = newTrigger()
.withIdentity("trigger7", "group1")
.withSchedule(simpleSchedule()
.withIntervalInMinutes(5)
.repeatForever())
.endAt(dateOf(22, 0, 0))
.build();

Build a trigger that will fire at the top of the next hour, then repeat every 2 hours, forever:

trigger = newTrigger()
.withIdentity("trigger8") // because group is not specified, "trigger8" will be in the default group
.startAt(evenHourDate(null)) // get the next even-hour (minutes and seconds zero ("00:00"))
.withSchedule(simpleSchedule()
.withIntervalInHours(2)
.repeatForever())
// note that in this example, 'forJob(..)' is not called
// - which is valid if the trigger is passed to the scheduler along with the job
.build(); scheduler.scheduleJob(trigger, job);

最后,还有一些高级知识,比如listener, 序列化等等知识,用不到就暂时不看了。

Quatz入门的更多相关文章

  1. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  2. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

  3. Oracle分析函数入门

    一.Oracle分析函数入门 分析函数是什么?分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计 ...

  4. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

  5. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  6. Angular2入门系列教程4-服务

    上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...

  7. wepack+sass+vue 入门教程(三)

    十一.安装sass文件转换为css需要的相关依赖包 npm install --save-dev sass-loader style-loader css-loader loader的作用是辅助web ...

  8. wepack+sass+vue 入门教程(二)

    六.新建webpack配置文件 webpack.config.js 文件整体框架内容如下,后续会详细说明每个配置项的配置 webpack.config.js直接放在项目demo目录下 module.e ...

  9. wepack+sass+vue 入门教程(一)

    一.安装node.js node.js是基础,必须先安装.而且最新版的node.js,已经集成了npm. 下载地址 node安装,一路按默认即可. 二.全局安装webpack npm install ...

随机推荐

  1. WebUpload formdata 上传参数

    https://www.cnblogs.com/wisdo/p/6159761.html webUploader 是款很好用的优秀的开源上传组件,由百度公司开发,详细的介绍可参见webUploader ...

  2. Spring Cloud Eureka 集群搭建 - 以及发现一个 “直觉BUG”

    首先解释一下标题所说的“直觉BUG”,这个是我自己的定义.就是我们直觉上认为这是一个BUG,是一个错误,而实际并没有出错. 比如下图: 虽然出现报错信息,但是,整个程序并没有出错.至于原因,图片上的文 ...

  3. Linux下 mkdir 命令详解

    一次性地建立多级目录,则可以使用-p参数 # mkdir -p /home/dir1/dir2/dir3

  4. JS 控制页面超时后自动跳转到登陆页面

    <span style="font-size: small;"><script language="javascript"> var m ...

  5. 【转】MYSQL数据库四种索引类型的简单使用--MYSQL组合索引“最左前缀”原则

    MYSQL数据库索引类型包括普通索引,唯一索引,主键索引与组合索引,这里对这些索引的做一些简单描述: (1)普通索引 这是最基本的MySQL数据库索引,它没有任何限制.它有以下几种创建方式: 创建索引 ...

  6. 安装JDK时提示 IllegalArgumentException:Invalid characters in hostname的解决方法

    今天在windows7_x64上安装JDK的时候提示IllegalArgumentException:Invalid characters in hostname, 解决方法: 1.打开[控制面板\系 ...

  7. 自然语言交流系统 phxnet团队 创新实训 个人博客 (三)

    因为需要处理自然语言的括号切分问题,专门记录下. import java.util.Scanner; import java.util.Stack; /** * @author Owner * */ ...

  8. Network In Network——卷积神经网络的革新

    Network In Network 是13年的一篇paper 引用:Lin M, Chen Q, Yan S. Network in network[J]. arXiv preprint arXiv ...

  9. 成功安装vscode中go的相关插件

    让你成功安装vscode中go的相关插件 注意:该演示环境是windows环境,linux和mac环境操作思路一样 vscode中有很多go的相关插件,非常好用如下:gocodegopkgsgo-ou ...

  10. 安卓横竖屏切换时activity的生命周期

    关于Activity横竖屏切换的声明周期变化: 1.新建一个Activity并把各个生命周期打印出来 2.运行Activity,得到如下信息 onCreate-->onStart-->on ...