Quartz Scheduler Calendar日历的使用
Quartz Calendar 日历的使用
quartz引擎为我们提供了日历的功能,让我们可以自己定义一个时间段,可以控制触发器在这个时间段内触发或者不触发,比如可以设置节假日,工作时间早8晚5等等。
下面这张表是quartz为我们提供的所有日历组件,我们可以根据具体需求选择使用,并且还支持扩展。
AnnualCalendar | This implementation of the Calendar excludes a set of days of the year. |
BaseCalendar | This implementation of the Calendar may be used (you don't have to) as a base class for more sophisticated one's. |
CronCalendar | This implementation of the Calendar excludes the set of times expressed by a given CronExpression . |
DailyCalendar | This implementation of the Calendar excludes (or includes - see below) a specified time range each day. |
HolidayCalendar | This implementation of the Calendar stores a list of holidays (full days that are excluded from scheduling). |
MonthlyCalendar | This implementation of the Calendar excludes a set of days of the month. |
WeeklyCalendar | This implementation of the Calendar excludes a set of days of the week. |
一、AnnualCalendar
This implementation of the Calendar excludes a set of days of the year. You may use it to exclude bank holidays which are on the same date every year
年度日历,这个日历可以设置一组日期的集合,当与trigger关联后,trigger在设定的这些日期之内都不会触发。
// Add the holiday calendar to the schedule
AnnualCalendar holidays = new AnnualCalendar();
//这里设置日期 年月日
//注意这里的一个坑(研究了大变天才发现坑在这里),就是月份要比实际月份少一个月
//2014,7,21 实际是2014年8月21日
Calendar calendar = new GregorianCalendar(2014, 7, 21);
holidays.setDayExcluded(calendar, true);
// tell the schedule about our holiday calendar
sched.addCalendar("holidays", holidays, false, false);
触发器每隔一小时触发一次,并与"holidays"关联,当日期到达上面设置的日期的时候,触发器不触发。
SimpleTrigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInHours(1)
.repeatForever())
.modifiedByCalendar("holidays")
.build();
看完上面例子的同学是不是认为 日历设置成2014-07-21 只有在2014年才生效,这里也是一个坑(官方汶上上有说明(上面红色)),一定要注意这里设置的年是没有意义的。它会在每一年的这个日期都生效
下面是它计算时间的源码,看到没,并没有计算设置的年份。
public boolean isDayExcluded(java.util.Calendar day) { if (day == null) {
throw new IllegalArgumentException(
"Parameter day must not be null");
} // Check baseCalendar first
if (! super.isTimeIncluded(day.getTime().getTime())) {
return true;
} int dmonth = day.get(java.util.Calendar.MONTH);
int dday = day.get(java.util.Calendar.DAY_OF_MONTH); if (dataSorted == false) {
Collections.sort(excludeDays, new CalendarComparator());
dataSorted = true;
} Iterator<java.util.Calendar> iter = excludeDays.iterator();
while (iter.hasNext()) {
java.util.Calendar cl = (java.util.Calendar) iter.next(); // remember, the list is sorted
if (dmonth < cl.get(java.util.Calendar.MONTH)) {
return false;
} if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) {
continue;
} if (dmonth != cl.get(java.util.Calendar.MONTH)) {
continue;
} return true;
} return false;
}
二、BaseCalendar
This implementation of the Calendar may be used (you don't have to) as a base class for more sophisticated one's.
它是一个基类,为上面表格中的各种日历提供了一些基础的方法,如果我们需要自定义日期可以继承它,正常情况我们使用quartz为我们提供好的日历就足够了。
三、CronCalendar
This implementation of the Calendar excludes the set of times expressed by a given CronExpression. For example, you could use this calendar to exclude all but business hours (8AM - 5PM) every day using the expression "* * 0-7,18-23 ? * *".
Cron表达式日历,可以写一个表达式来排除一个时间范围,比如可以设置为排除所有的时间,但是工作时间除外,也就是 在早8点-晚5点触发,其他时间暂停。
CronCalendar calendar = new CronCalendar("* * 0-7,18-23 ? * *");
sched.addCalendar("business", calendar, false, false);
四、DailyCalendar
This implementation of the Calendar excludes (or includes - see below) a specified time range each day. For example, you could use this calendar to exclude business hours (8AM - 5PM) every day. Each DailyCalendar only allows a single time range to be specified, and that time range may not cross daily boundaries (i.e. you cannot specify a time range from 8PM - 5AM). If the property invertTimeRange is false (default), the time range defines a range of times in which triggers are not allowed to fire. If invertTimeRange is true, the time range is inverted – that is, all times outside the defined time range are excluded. Note when using DailyCalendar, it behaves on the same principals as, for example, WeeklyCalendar. WeeklyCalendar defines a set of days that are excluded every week. Likewise, DailyCalendar defines a set of times that are excluded every day.
时间范围日历,定义一个时间范围,可以让触发器在这个时间范围内触发,或者在这个时间范围内不触发,每一个DailyCalendar的实例只能设置一次时间范围,并且这个时间范围不能超过一天的边界,比如你不能定义一个时间范围是(晚上8点至第二天早上5点),如果invertTimeRange这个属性等于false(默认),那么定义的时间范围内触发器不会触发,相反如果invertTimeRange=true 那么只有在这个时间范围内触发器才会触发,这个时间范围以外的时间都被排除。
定义一个时间范围 s=当前时间 e=当前时间+10秒钟。
然后创建一个触发器立即触发,时间间隔3秒,无限重复。
invertTimeRange=true 这个触发器会在s-e这个时间范围内触发,invertTimeRange=false 这个触发器会在s-e这个时间范围之外触发。
DailyCalendar的构造参数也支持String new DailyCalendar("20:57:00", "20:59:00"),还有其他很多方式可以参见官方文档。
Calendar s = Calendar.getInstance();
s.setTime(new Date()); Calendar e = Calendar.getInstance();
e.setTime(futureDate(10, IntervalUnit.SECOND)); DailyCalendar dailyCalendar = new DailyCalendar(s, e);
//DailyCalendar dailyCalendar = new DailyCalendar("20:57:00", "20:59:00");
dailyCalendar.setInvertTimeRange(true);
sched.addCalendar("dailyCalendar", dailyCalendar, false, false);
SimpleTrigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(simpleSchedule()
.withIntervalInSeconds(3)
.repeatForever())
.modifiedByCalendar("dailyCalendar")
.build();
五、HolidayCalendar
This implementation of the Calendar stores a list of holidays (full days that are excluded from scheduling). The implementation DOES take the year into consideration, so if you want to exclude July 4th for the next 10 years, you need to add 10 entries to the exclude list.
该日历与AnnualCalendar一致,区别就是设置的year是有效的,也就是说如果你希望在未来的10年中 7月4日这天 这个日历生效,那么你需要添加10个日期,分别是 2014-7-4 ,2015-7-4...... 2024-7-4 这样才行。
HolidayCalendar holidays = new HolidayCalendar();
Calendar calendar = new GregorianCalendar(2014, 7, 21);
holidays.addExcludedDate(calendar.getTime());
sched.addCalendar("holidays", holidays, false, false);
下面是查询排除日期的算法,getStartOfDayJavaCalendar是把分秒时毫秒都去掉 只留年月日 然后判断日期是否排除
@Override
public boolean isTimeIncluded(long timeStamp) {
if (super.isTimeIncluded(timeStamp) == false) {
return false;
} Date lookFor = getStartOfDayJavaCalendar(timeStamp).getTime(); return !(dates.contains(lookFor));
}
六、MonthlyCalendar
This implementation of the Calendar excludes a set of days of the month. You may use it to exclude every first day of each month for example. But you may define any day of a month.
月日历,你可以定义一个月当中的若干天,例如你可以设置每个月的第一天触发器不进行触发,当然你还可以定义一个月当中的任何一天。
下面例子给出每个月2,3,4号不触发的日历
MonthlyCalendar monthlyCalendar = new MonthlyCalendar();
monthlyCalendar.setDayExcluded(2, true);
monthlyCalendar.setDayExcluded(3, true);
monthlyCalendar.setDayExcluded(4, true);
sched.addCalendar("monthlyCalendar", monthlyCalendar, false, false);
七、WeeklyCalendar
This implementation of the Calendar excludes a set of days of the week. You may use it to exclude weekends for example. But you may define any day of the week. By default it excludes SATURDAY and SUNDAY.
星期日历,可以定义在一个星期当中的星期几几几 是不触发的日期,例如你可以定义么每个周末(星期天)触发器不触发,你也可以定义一周当中的任何一天或是几天。默认情况SATURDAY ,SUNDAY 这两天是没排除的。
下面的例子设置了每个星期四触发器不触发,并且默认情况周六和周天也是不触发的,这个是默认设置。如果需要周六周日也触发,那么把它清掉就可以了(weeklyCalendar.setDayExcluded(Calendar.SATURDAY , false)像这样)。一个需要注意的地方就是传入参数不能直接写数字星期几,因为老外的日子计算的与我们不一样,需要传入(java.util.Calendar)的常量字段,这样才准确。
WeeklyCalendar weeklyCalendar = new WeeklyCalendar();
weeklyCalendar.setDayExcluded(Calendar.THURSDAY, true);
sched.addCalendar("weeklyCalendar", weeklyCalendar, false, false);
八、组合日历的使用
上面的例子都是每一个触发器(trigger)关联一个日历的例子,我们在构建触发器的时候通过.modifiedByCalendar("日历的key")关联一个注册到引擎当中的日历,这种情况已经能够满足我们大部分的需求。
但是系统的需求往往是复杂多变的,假设有这样一种情况,需要一个触发器在 每周一到周五,早8点-晚晚5点 每隔1小时执行,那么该如何使用日历呢?
其实我们不用日历,使用一个CronTrigger也是可以搞定的,我们这里只不过是抛砖引玉而已。
那让我们来写一个组合日历使用的例子:
DailyCalendar dailyCalendar = new DailyCalendar("8:00:00", "17:00:00");
dailyCalendar.setInvertTimeRange(false); WeeklyCalendar weeklyCalendar = new WeeklyCalendar(dailyCalendar);
sched.addCalendar("weeklyCalendar", weeklyCalendar, false, false);
我们写一个时间间隔的日历dailyCalendar,将其作为参数传递给weeklyCalendar就可以了,这样引擎在计算日历日期的时候会先判断dailyCalendar的时间范围,然后再判断weeklyCalendar是时间范围,当条件都满足的是否,触发器才会被触发,我们分析一下源码:
@Override
public boolean isTimeIncluded(long timeStamp) {
if (excludeAll == true) {
return false;
} // Test the base calendar first. Only if the base calendar not already
// excludes the time/date, continue evaluating this calendar instance.
if (super.isTimeIncluded(timeStamp) == false) { return false; } java.util.Calendar cl = createJavaCalendar(timeStamp);
int wday = cl.get(java.util.Calendar.DAY_OF_WEEK); return !(isDayExcluded(wday));
}
我们发现它首先调用 if (super.isTimeIncluded(timeStamp) == false) { return false; } 奥秘就在这里,我们继续看。
public boolean isTimeIncluded(long timeStamp) { if (timeStamp <= 0) {
throw new IllegalArgumentException(
"timeStamp must be greater 0");
} if (baseCalendar != null) {
if (baseCalendar.isTimeIncluded(timeStamp) == false) { return false; }
} return true;
}
这里先判断了baseCalendar,这个对象就是在构造参数传递进去的dailyCalendar , 也就是它先试用dailyCalendar 进行日期计算,然后自己在计算,这样就完成了日历的组合使用。
最后在补充说明一下往quartz的引擎中注册日历的方法。
addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)
这个方法有四个参数
1、calName 日历的名字,在构建触发器时通过modifiedByCalendar("")这里使用。
2、calendar 日历对象。
3、replace 当日历已经存在的情况下是否替换,true=替换, false=不替换 如果不替换还出现重复的情况会抛出异常。
4、updateTriggers 这个参数比较重要,它的意思是当一个已经存在与调度引擎中的触发器,并且已经引用了一个日历,比如:一个(触发器A)关联了一个日历,这个日历过滤每个星期日。
现在过了一段时间这个日历更新了(星期六也过滤),那么这个属性是用来指示触发器是否使用新的日历。不然的话(触发器A)仍然使用旧版本的日历,如果在有新添加到引擎中的触发器才会使用新日历。
我们看一下源码:RAMJobStore 还有其它的Store原理也都一样。
public void storeCalendar(String name,
Calendar calendar, boolean replaceExisting, boolean updateTriggers)
throws ObjectAlreadyExistsException { calendar = (Calendar) calendar.clone(); synchronized (lock) { Object obj = calendarsByName.get(name); if (obj != null && replaceExisting == false) {
throw new ObjectAlreadyExistsException(
"Calendar with name '" + name + "' already exists.");
} else if (obj != null) {
calendarsByName.remove(name);
} calendarsByName.put(name, calendar); if(obj != null && updateTriggers) {
Iterator<TriggerWrapper> trigs = getTriggerWrappersForCalendar(name).iterator();
while (trigs.hasNext()) {
TriggerWrapper tw = trigs.next();
OperableTrigger trig = tw.getTrigger();
boolean removed = timeTriggers.remove(tw); trig.updateWithNewCalendar(calendar, getMisfireThreshold()); if(removed) {
timeTriggers.add(tw);
}
}
}
}
}
Quartz Scheduler Calendar日历的使用的更多相关文章
- Quartz Scheduler(2.2.1) - Usage of Calendars
Quartz Calendar objects (not java.util.Calendar objects) can be associated with triggers at the time ...
- Quartz Scheduler 开发指南(1)
Quartz Scheduler 开发指南(1) 原文地址:http://www.quartz-scheduler.org/generated/2.2.2/html/qtz-all/ 实例化调度程序( ...
- spring集成quartz scheduler
创建项目 有两种创建quart配置作业 1.使用MethodInvokingJobDetailFactoryBean Quartz Scheduler 配置作业(MethodInvokingJobD ...
- Table of Contents - Quartz Scheduler
Getting Started Hello World Integration with Spring Quartz Scheduler Developer Guide Usage of JobDat ...
- Quartz Scheduler(2.2.1) - hello world
简单示例 1. maven 依赖 <dependencies> <dependency> <groupId>org.quartz-scheduler</gro ...
- Quartz Scheduler(2.2.1) - Working with JobStores
About Job Stores JobStores are responsible for keeping track of all the work data you give to the sc ...
- 最新 Spring 4.2.2 集成 Quartz Scheduler 2.2.2 任务调度示例
参考http://blog.csdn.net/defonds/article/details/49496895 本文将演示如何通过 Spring 使用 Quartz Scheduler 进行任务调度. ...
- 【转】Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历))
Python3 日期时间 相关模块(time(时间) / datatime(日期时间) / calendar(日历)) 本文由 Luzhuo 编写,转发请保留该信息. 原文: http://blog. ...
- 整合shiro出现【Correct the classpath of your application so that it contains a single, compatible version of org.quartz.Scheduler】
跑的时候出现错误: Description: An attempt was made to call the method org.quartz.Scheduler.getListenerManage ...
随机推荐
- Redis 的安装与使用(单节点)
Redis 的安装与使用(单节点) 环境:CentOS 6.5 Redis 版本:redis-3.0 (考虑到Redis3.0 在集群和性能提升方面的特性,rc 版为正式版的候选版,而且 很快就出 ...
- Java Nashorn--Part 3
jjs 的 -Scripting 选项 jjs shell 是一个不错的方法来测试一些基本的 JavaScript,或者于不太熟悉的 JavaScript包进行交互(主要是指 javax.script ...
- 查看指定java进程的jvm参数配置命令之jinfo
一.查看所有的参数 jinfo -flags PS:3739为JAVA进程ID Attaching to process ID , please wait... Debugger attached s ...
- SIMULINK的模块库介绍
SIMILINK模块库按功能进行分为以下8类子库:Continuous(连续模块)Discrete(离散模块)Function&Tables(函数和平台模块)Math(数学模块)Nonline ...
- 永久代 PermGen 简述
永久代(PermGen) 绝大部分 Java 程序员应该都见过 “java.lang.OutOfMemoryError: PermGen space “这个异常.这里的 “PermGen space” ...
- Python 爬虫编码格式问题 gb2312转换utf8
遇到的问题是:爬取网页得到的结果如下(部分) 里面的中文出现乱码. <!DOCTYPE html> <html lang='zh-CN'> <head> < ...
- notepad++添加插件管理器
notepad++ 是一个很不错的文本编辑器,添加一些插件可以更好地使用. 首先需要使用插件管理器,最新版本的github地址是:https://github.com/bruderstein/nppp ...
- MySQL update 语句与标准SQL不同的地方
[SQL标准中有一个叫同时执行的概念] 同时执行指的是在同一个子句中的各个部分的执行时机是不区分先后的,如下面的SQL语句 ),); +---------+--------+ ) ) | +----- ...
- python 取整的两种方法
问题简介: 要把一个浮点数(float)整数部分提取出来.比如把“2.1”变成“2”的这一过程:现在我们给这个过程起一个名字叫“取整”.那么它 在python中大致可以有两种写法 写法1)类型转换: ...
- 有关 Windows 10 中“适用于 Linux 的 Windows 子系统(Beta)”
1.如何启用?(未来应该可从应用商店中直接安装) 在"控制面板"的"启用或关闭 Windows 功能"中进行勾选安装.(安装完成后需要重新启动) 2.然后呢? ...