赞
踩
原文:https://maiyikai.github.io/2019/12/27/1577427502
项目中,或多或少都会使用到定时器,定时执行某些特殊得功能。而在 SpringBoot 项目中,使用得定时器功能就是使用 @Scheduled
注解。
当然,定时器功能打开了,但是没有定时,这是不可行的。所以,在定时器使用中,使用 Cron 表达式作为定时器规则,在 @Scheduled
注解源码中可以看到,除了 cron
属性之外还有多个功能不一的属性。
这里主要简述的是 Cron 表达式,在版本 1.5.6 版本的 SpringBoot 工程中,解析 Cron 表达式的源码如下(源码地址:org.springframework.scheduling.support.CronTrigger):
private void parse(String expression) throws IllegalArgumentException { String[] fields = StringUtils.tokenizeToStringArray(expression, " "); if (fields.length != 6) { throw new IllegalArgumentException(String.format( "Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression)); } setNumberHits(this.seconds, fields[0], 0, 60); setNumberHits(this.minutes, fields[1], 0, 60); setNumberHits(this.hours, fields[2], 0, 24); setDaysOfMonth(this.daysOfMonth, fields[3]); setMonths(this.months, fields[4]); setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8); if (this.daysOfWeek.get(7)) { // Sunday can be represented as 0 or 7 this.daysOfWeek.set(0); this.daysOfWeek.clear(7); } }
从以上源码看出,当前版本的 SpringBoot 中,针对于 @Scheduled
的 Cron 表达式,只支持 6 位规则,而在网上有资料表示可以存在 7 位。
但是源码中,限制了只能有 6 位,否则抛出异常。
Cron 表达是对应的内容为: seconds minutes hours daysOfMonth months daysOfWeek
。
针对不同属性解释:
在解释这个规则时,都是用了相同的两个方法,源码如下:
private void setNumberHits(BitSet bits, String value, int min, int max) { String[] fields = StringUtils.delimitedListToStringArray(value, ","); for (String field : fields) { if (!field.contains("/")) { // Not an incrementer so it must be a range (possibly empty) int[] range = getRange(field, min, max); bits.set(range[0], range[1] + 1); } else { String[] split = StringUtils.delimitedListToStringArray(field, "/"); if (split.length > 2) { throw new IllegalArgumentException("Incrementer has more than two fields: '" + field + "' in expression \"" + this.expression + "\""); } int[] range = getRange(split[0], min, max); if (!split[0].contains("-")) { range[1] = max - 1; } int delta = Integer.valueOf(split[1]); if (delta <= 0) { throw new IllegalArgumentException("Incrementer delta must be 1 or higher: '" + field + "' in expression \"" + this.expression + "\""); } for (int i = range[0]; i <= range[1]; i += delta) { bits.set(i); } } } } private int[] getRange(String field, int min, int max) { int[] result = new int[2]; if (field.contains("*")) { result[0] = min; result[1] = max - 1; return result; } if (!field.contains("-")) { result[0] = result[1] = Integer.valueOf(field); } else { String[] split = StringUtils.delimitedListToStringArray(field, "-"); if (split.length > 2) { throw new IllegalArgumentException("Range has more than two fields: '" + field + "' in expression \"" + this.expression + "\""); } result[0] = Integer.valueOf(split[0]); result[1] = Integer.valueOf(split[1]); } if (result[0] >= max || result[1] >= max) { throw new IllegalArgumentException("Range exceeds maximum (" + max + "): '" + field + "' in expression \"" + this.expression + "\""); } if (result[0] < min || result[1] < min) { throw new IllegalArgumentException("Range less than minimum (" + min + "): '" + field + "' in expression \"" + this.expression + "\""); } return result; }
每个域都使用数字,或者使用连接符连接,含义:
注:在源码中未使用到的特殊符号有 L (表最后)、 W (表有效工作日)、 LW (表最后某月最后一个工作日)、 # (表用于确定每个月第几个星期几)
一些常用的例子,这里用表格展示:
规则 | 解释 |
---|---|
0 0 10,14,16 * * ? | 每天上午10点,下午2点,4点 |
0 0/30 9-17 * * ? | 朝九晚五工作时间内每半小时 |
0 0 12 ? * WED | 表示每个星期三中午12点 |
0 0 12 * * ? | 每天中午12点触发 |
0 15 10 ? * * | 每天上午10:15触发 |
0 15 10 * * ? | 每天上午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触发 |
文章所述与网上资料有所不同,需要根据源码判断,是否正确使用。
根据目前 SpringBoot 版本 1.5.6 来看,对于 Cron 表达式的使用相对简单。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。