实例解析概念

在quartz中,有几个核心类和接口:Job、JobDetail、Trigger、Calendar、Scheduler。
下面我们结合实例来分析这些类的角色定位。
现在我们有一个新闻网站,它有一张任务日志表,记录着我们的不同任务,比如每隔三十分钟要根据文章的阅读量和评论量来生成我们的最热文章列表。在每天早晚12点,定时从其他新闻网站扒取一定量新闻,在每周一晚上12点到3点进行论坛封闭维护,而如果遇到节假日则不维护等。在以上实例中:

  1. 生成最热文章,扒取新闻,论坛封闭维护都是我们的Job,它定义了我们的需要执行的任务,是一个抽象的接口.
  2. 如果我们要具体到每隔三十分钟生成最热文章,早晚12点扒取新闻等,在我们的具体任务执行时刻,我们就需要能够描述Job及其他相关静态信息的jobDetail,它相当于是我们的Job+具体实现细节
  3. 而Trigger则描述了Job执行的时间触发规则,比如每隔三十分钟、早晚12点等
  4. 而这里的Calendar可以看成是一些日历特定时间点的集合,比如我们这里遇到节假日则不维护,节假日如国庆节、愚人节等等,都是我们的日历特定时间点。
  5. 而Scheduler就是我们的任务日志表,它是一个容器,记载(容纳)了我们前面的工作、触发时间等内容。

具体用法详解

通过实例,我们对quartz的核心类有了较清晰的功能定位,根据Quratz的不同版本,这几个核心类有较大改动,具体的操作不太相同,但是思路是相同的;比如1.+版本jar包中,JobDetail是个类,直接通过构造方法与Job类关联。SimpleTrigger和CornTrigger是类;在2.+jar包中,JobDetail是个接口,SimpleTrigger和CornTrigger是接口。下面详细地分析它们的具体用法:

1. Job

Job是一个接口,只有一个void execute(JobExecutionContext jec)方法,JobExecutionContext提供了我们的任务调度上下文信息,比如,我们可以通过JobExecutionContext获取job相对应的JobDetail、Trigger等信息,我们在配置自己的内容时,需要实现此类,并在execute中重写我们的任务内容。下面是我们的扒取新闻工作实例:

public class pickNewsJob implements Job {

    @Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println("在"+sdf.format(new Date())+"扒取新闻");
}
}

2. JobDetail

Quartz在每次执行任务时,都会创建一个Job实例,并为其配置上下文信息,jobDetail有一个成员属性JobDataMap,存放了我们Job运行时的具体信息,在后面我们会详细提到。
1. 在1.+版本中,它作为一个类,常用的构造方法有:JobDetail(String name, String group, Class jobClass),我们需要指定job的名称,组别和实现了Job接口的自定义任务类。实例如JobDetail jobDetail =new JobDetail("job1", "jgroup1", pickNewsJob.class);
2. 而在2.+版本中,我们则通过一下方法创建 JobBuilder.newJob(自定义任务类).withIdentity(任务名称,组名).build();实例如JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class).withIdentity(“job1”,”group1”).build();`

3. Scheduler

先讲Scheduler,方便后讲解Trigger时测试。
Scheduler作为我们的“任务记录表”,里面(可以)配置大量的Trigger和JobDetail,两者在 Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。下面是使用Schduler的实例:

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//将jobDetail和Trigger注册到一个scheduler里,建立起两者的关联关系
scheduler.scheduleJob(jobDetail,Trigger); scheduler.start();//开始任务调度

在一个scheduler被创建后,它处于”STAND-BY”模式,在触发任何job前需要使用它的start()方法来启动。同样的,如果我们想根据我们的业务逻辑来停止定时方案执行,可以使用scheduler.standby()方法

3. Trigger

Trigger描述了Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger两个子类。

1. SimpleTrigger

如果嵌入事件机制只触发一次,或意图使Job以固定时间间隔触发,则使用SimpleTrigger较合适,它有多个构造函数,其中一个最复杂的构造函数为:
SimpleTrigger(String name, String group, String jobName, String jobGroup, Date startTime, Date
endTime, int repeatCount, long repeatInterval)
参数依次为触发器名称、触发器所在组名、工作名、工作所在组名、开始日期、结束日期、重复次数、重复间隔。
1. 如果我们不需同时设置这么多属性,可调用其他只有部分参数的构造方法,其他参数也可以通过set方法动态设置。
2. 这里需要注意的是,如果到了我们设置的endTime,即时重复次数repeatCount还没有达到我们预设置的次数。任务也不会再此执行。
下面是1.+版本的创建实例

//创建一个触发器,使任务从现在开始、每隔两秒执行一次,共执行10次
SimpleTrigger simpleTrigger = new SimpleTrigger("triiger1");//至少需要设置名字以标识当前触发器,否则在调用时会报错
simpleTrigger.setStartTime(new Date());
simpleTrigger.setRepeatInterval(2000);
simpleTrigger.setRepeatCount(10);

下面是2.+版本的创建实例

SimpleTrigger simpleTrigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger1")//配置触发器名称
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))//配置重复次数和间隔时间
.startNow()//设置从当前开始
.build();//创建操作

通过TriggerBuilder,我们可以通过方法方便地配置触发器的各种参数。

2. CronTrigger

通过Cron表达式定义复杂的时间调度方案,具体内容我们在下一篇详细提到

4. Calendar

在实际的开发中,我们可能需要根据节假日来调整我们的任务调度方案。实例如下:

//第一步:创建节假日类
// ②四一愚人节
Calendar foolDay = new GregorianCalendar(); //这里的Calendar是 java.util.Calendar。根据当前时间所在的默认时区创建一个“日子”
foolDay.add(Calendar.MONTH, 4);
foolDay.add(Calendar.DATE, 1);
// ③国庆节
Calendar nationalDay = new GregorianCalendar();
nationalDay.add(Calendar.MONTH, 10);
nationalDay.add(Calendar.DATE, 1); //第二步:创建AnnualCalendar,它的作用是排除排除每一年中指定的一天或多天
AnnualCalendar holidays = new AnnualCalendar();
//设置排除日期有两种方法
// 第一种:排除的日期,如果设置为false则为包含(included)
holidays.setDayExcluded(foolDay, true);
holidays.setDayExcluded(nationalDay, true);
//第二种,创建一个数组。
ArrayList<Calendar> calendars = new ArrayList<Calendar>();
calendars.add(foolDay);
calendars.add(nationalDay);
holidays.setDaysExcluded(calendars); //第三步:将holidays添加进我们的触发器
simpleTrigger.setCalendarName("holidays"); //第四步:设置好然后需要在我们的scheduler中注册
scheduler.addCalendar("holidays",holidays, false,false);,注意这里的第一个参数为calendarName,需要和触发器中添加的Calendar名字像对应。

在这里,除了可以使用AnnualCalendar外,还有CronCalendar(表达式),DailyCalendar(指定的时间范围内的每一天),HolidayCalendar(排除节假日),MonthlyCalendar(排除月份中的数天),WeeklyCalendar(排除星期中的一天或多天)

至此,我们的核心类基本讲解完毕,下面附上我们的完整测试代码:

/*********************1.+版本*********************/
public class pickNewsJob implements Job { @Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println("在" + sdf.format(new Date()) + "扒取新闻");
} public static void main(String args[]) throws SchedulerException {
JobDetail jobDetail =new JobDetail("job1", "jgroup1", pickNewsJob.class);
SimpleTrigger simpleTrigger = new SimpleTrigger("triiger1");
simpleTrigger.setStartTime(new Date());
simpleTrigger.setRepeatInterval(2000);
simpleTrigger.setRepeatCount(10);
simpleTrigger.setCalendarName("holidays"); //设置需排除的特殊假日
AnnualCalendar holidays = new AnnualCalendar();
// 四一愚人节
Calendar foolDay = new GregorianCalendar(); // 这里的Calendar是 ava.util.Calendar。根据当前时间所在的默认时区创建一个“日子”
foolDay.add(Calendar.MONTH, 4);
foolDay.add(Calendar.DATE, 1);
// 国庆节
Calendar nationalDay = new GregorianCalendar();
nationalDay.add(Calendar.MONTH, 10);
nationalDay.add(Calendar.DATE, 1);
//排除的日期,如果设置为false则为包含(included)
holidays.setDayExcluded(foolDay, true);
holidays.setDayExcluded(nationalDay, true);
/*方法2:通过数组设置
ArrayList<Calendar> calendars = new ArrayList<Calendar>();
calendars.add(foolDay);
calendars.add(nationalDay);
holidays.setDaysExcluded(calendars);*/ //创建scheduler
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.addCalendar("holidays", holidays, false, false); scheduler.scheduleJob(jobDetail, simpleTrigger);
scheduler.start(); }
}
/*******************2.+版本***************/
public class pickNewsJob implements Job { @Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println("在"+sdf.format(new Date())+"扒取新闻");
} public static void main(String args[]) throws SchedulerException {
JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class)
.withIdentity("job1", "group1").build();
SimpleTrigger simpleTrigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger1")
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))
.startNow()
.build(); //设置需排除的特殊假日
AnnualCalendar holidays = new AnnualCalendar();
// 四一愚人节
Calendar foolDay = new GregorianCalendar(); // 这里的Calendar是 ava.util.Calendar。根据当前时间所在的默认时区创建一个“日子”
foolDay.add(Calendar.MONTH, 4);
foolDay.add(Calendar.DATE, 1);
// 国庆节
Calendar nationalDay = new GregorianCalendar();
nationalDay.add(Calendar.MONTH, 10);
nationalDay.add(Calendar.DATE, 1);
//排除的日期,如果设置为false则为包含(included)
holidays.setDayExcluded(foolDay, true);
holidays.setDayExcluded(nationalDay, true);
/*方法2:通过数组设置
ArrayList<Calendar> calendars = new ArrayList<Calendar>();
calendars.add(foolDay);
calendars.add(nationalDay);
holidays.setDaysExcluded(calendars);*/ //创建scheduler
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.addCalendar("holidays", holidays, false, false); scheduler.scheduleJob(jobDetail, simpleTrigger);
scheduler.start();
}
}

可见,两个不同版本的主要区别在于JobDetail和Triiger的配置。

此外,除了使用scheduler.scheduleJob(jobDetail, simpleTrigger)来建立jobDetail和simpleTrigger的关联外,在1.+版本中的配置还可以采用如下所示方式

simpleTrigger.setJobName("job1");//jobName和我们前面jobDetail的的名字一致
simpleTrigger.setJobGroup("jgroup1");//jobGroup和我们之前jobDetail的组名一致
scheduler.addJob(jobDetail, true);//注册jobDetail,此时jobDetail必须已指定job名和组名,否则会抛异常Trigger's related Job's name cannot be null
scheduler.scheduleJob(simpleTrigger);//注册triiger必须在注册jobDetail之后,否则会抛异常Trigger's related Job's name cannot be null

这里还需要注意的是,如果我们使用scheduler.addCalendar("holidays", holidays, false, false)必须在向scheduler注册trigger之前scheduler.scheduleJob(simpleTrigger),否则会抛异常:Calendar not found: holidays

而在2.+版本中,我尝试在创建triiger时用forJob(“job1”, “jgroup1”)来绑定job名和组名

SimpleTrigger simpleTrigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger1")
.forJob("job1", "jgroup1")//在这里绑定
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(10, 2))
.startNow()
.build();

//后面是一样的
scheduler.addJob(jobDetail, true);
scheduler.scheduleJob(simpleTrigger);

Quartz任务调度(1)概念例析快速的更多相关文章

  1. (转)Quartz任务调度(1)概念例析快速入门

    http://blog.csdn.net/qwe6112071/article/details/50991563 Quartz框架需求引入 在现实开发中,我们常常会遇到需要系统在特定时刻完成特定任务的 ...

  2. Spring研磨分析、Quartz任务调度、Hibernate深入浅出系列文章笔记汇总

    Spring研磨分析.Quartz任务调度.Hibernate深入浅出系列文章笔记汇总 置顶2017年04月27日 10:46:45 阅读数:1213 这系列文章主要是对Spring.Quartz.H ...

  3. Quartz任务调度(4)JobListener分版本超详细解析

    JobListener 我们的jobListener实现类必须实现其以下方法: 方法 说明 getName() getName() 方法返回一个字符串用以说明 JobListener 的名称.对于注册 ...

  4. Quartz任务调度快速入门

    Quartz任务调度快速入门 概述 了解Quartz体系结构 Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的 ...

  5. Dubbo学习系列之十二(Quartz任务调度)

    Quartz词义为"石英"水晶,然后聪明的人类利用它发明了石英手表,因石英晶体在受到电流影响时,它会产生规律的振动,于是,这种时间上的规律,也被应用到了软件界,来命名了一款任务调度 ...

  6. 从零开始学 Java - Spring 使用 Quartz 任务调度定时器

    生活的味道 睁开眼看一看窗外的阳光,伸一个懒腰,拿起放在床一旁的水白开水,甜甜的味道,晃着尾巴东张西望的猫猫,在窗台上舞蹈.你向生活微笑,生活也向你微笑. 请你不要询问我的未来,这有些可笑.你问我你是 ...

  7. Quartz任务调度

    狂神声明 : 文章均为自己的学习笔记 , 转载一定注明出处 ; 编辑不易 , 防君子不防小人~共勉 ! Quartz任务调度 课程目标 : 了解Quartz框架 : 任务(Job)  触发器(Trig ...

  8. Quartz任务调度实践

    最近在写一个任务调度程序,需要每隔几秒查询数据库,并取出数据做一些处理操作.使用到了Quartz任务调度框架. 基本概念 Quartz包含几个重要的对象,分别为任务(Job),触发器(Trigger) ...

  9. Quartz任务调度入门

    Quartz任务调度入门 了解Quartz体系结构Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念 ...

随机推荐

  1. web自动化之浏览器启动

    一.环境准备 1.本地引入jar 从http://selenium-release.storage.googleapis.com/index.html?path=3.9/,下载selenium-ser ...

  2. Nacos 2.0源码分析-拦截器机制

    温馨提示: 本文内容基于个人学习Nacos 2.0.1版本代码总结而来,因个人理解差异,不保证完全正确.如有理解错误之处欢迎各位拍砖指正,相互学习:转载请注明出处. Nacos服务端在处理健康检查和心 ...

  3. CF1214E Petya and Construction Set题解

    原来这就叫构造题,了 这道题的做法,我自己诌了一个形象的名字--"挂葡萄"法( 首先,"搭葡萄架":考虑到每个距离 \(d_i\) 只与 \(2i-1,2i\) ...

  4. Python中调用Java程序包

    <原创不易,转载请标明出处:https://www.cnblogs.com/bandaobudaoweng/p/10785766.html> 开发Python程序,需求中需要用到Java代 ...

  5. Django报错:'Specifying a namespace in include() without providing an app_name '

    环境:win10(64)+pycharm2018.3+python3.7 在网页项目中使用include()方法 项目目录中同时存在app/urls.py和proj/urls.py 在proj/url ...

  6. 构建前端第6篇之---内嵌css样式 <el-button style="width:100%"> 登录 </el-button>

    张艳涛写于2021-1-20日 What: 如何让button的长度和input长度一致呢 最先想到的是给这个button加一个class ="buttonclass",然后在vu ...

  7. JS进度条顺滑版实现

    进度条不顺滑 相信大多前端同学都自己写过音频.视频播放器,实现并不复杂.最近在小程序里,做了一个类似微博刷视频的需求.其中有一部分功能需要实现自定义进度条,在做完第一版之后发现进度条不顺滑,而后想查查 ...

  8. Java后端编译

    概述 如果我们把字节码看作是程序语言的一种中间表示形式(Intermediate Representation,IR)的话, 那编译器无论在何时.在何种状态下把Class文件转换成与本地基础设施(硬件 ...

  9. Kali中John的使用方法

    John是一个破解系统密码的工具. 参数 John the Ripper 1.9.0-jumbo-1 OMP [linux-gnu 64-bit x86_64 AVX AC] Copyright (c ...

  10. small-spring 代码贡献者3个月,敢说精通Spring了,分享我的总结!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.为什么手写Spring 这个与我们码农朝夕相处的 Spring,就像睡在你身边的媳妇,你知 ...