定时任务与cron表达式
前两天公司两个新同事接到了需求。每天晚上11点启动批量任务,往另一个关联系统里发送数据。接到需求,两个新同事愁眉不展,不知道该怎么做。跑过来问我有啥好方法,我问他们打算怎么做,他们说不清楚怎么办才好,甚至做好了加班的准备,两个人每天晚上轮流守着,等到11点启动了批量任务才回家睡觉。我一听,这还了得,每天守着就为了点下鼠标启动一下任务,青春大好时光怎么能浪费在加班上。索引我就给他们出了注意——定时任务,他们一听,喜笑颜开。
考虑到有的人使用的框架可能有所不同,我分了Springboot和普通Spring项目两种来给大家说明。
1. Springboot项目
如果SpringBoot项目启动定时任务,相对比较简单,按照下面的方式新建一个类即可。
@Configuration
@EnableScheduling
public class TimeTask {
@Scheduled(cron = "0/5 * * * * ?")
private void configureTasks() {
System.err.println("执行静态定时任务时间(TimerTask): " + LocalDateTime.now()+ "=======> 要发送邮件了");
}
}
注解的一些说明已经写得很清楚了,不在赘述,只需要写一个类即可。
2. Spring项目
如果你的框架用到了spring,一般项目都会用到,可以这样做。
- 在xml里加入task的命名空间
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
- 启动注解驱动的定时任务,这里有两种方式,一种是单线程,一种是多线程,择一即可,建议用多线程的
<task:annotation-driven/>
<task:scheduler id="scheduler" pool-size="7" />
说明:这里的两种,选择一种即可。我这里多线程的方式设置了线程池大小为7
- 编写定时任务的处理类
public class TimeTask {
public void timeTask1(){
System.err.println("执行静态定时任务时间(TimerTask): " + LocalDateTime.now()+ "=======> 要发送邮件了");
}
public void timeTask2(){
System.err.println("执行静态定时任务时间(TimerTask): " + LocalDateTime.now()+ "=======> 要填写工作日报了");
}
}
- 将该bean注册到spring中。
<bean id="timeTask" class="com.xxc.controller.TimeTask"/>
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="timeTask" method="timeTask1" cron="0/5 * * * * ?"/>
<task:scheduled ref="timeTask" method="timeTask2" cron="0/8 * * * * ?"/>
</task:scheduled-tasks>
有了这个类,你想加多少个定时任务,往里面加方法就好了。
3. 总结
对于上面两种方法,我们使用到的是cron表达式,这里给大家汇总一下。
cron表达式是一个字符串,字符串以空格隔开,分为5或6隔开,每一个域代表一个含义,系统支持的表达式格式如下:[DayofWeek]为选填。
字段含义
Second(秒):可出现” * / , - ”四个字符,有效范围为0-59
Minutes(分钟):可出现” * / , - ”四个字符,有效范围为0-59
Hour(时):可出现” * / , - ”四个字符,有效范围为0-23
DayofMonth(月中的某一天):可出现” * / , - ? ”五个字符,有效范围为0-31
Month(年中的某个月):可出现” , - * / ”四个字符,有效范围为1-12的整数或JAN-DEC
DayofWeek(星期几):可出现" * / , - ? "五个字符,有效范围为0-6的整数或SUM-SAT两个范围,0表示星期天,1表示星期一,以此类推。
字符含义
* 表示匹配该域的任意值,假如在Minutes域使用*,即表示每分钟都会触发事件。
? 仅被用于天(月)和天(星期)两个子表达式,表示不指定值,当两个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为” ? ”。
- 表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次。
/ 表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次。
, 表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分钟分别触发一次。
举例
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 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发一次
0 10,44 14 ? 3 WED 每年的三月的星期三的下午2:10和2:44触发
0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
L:表示last,例如星期中表示7或SAT,月份中表示最后一天31或30,6L表示这个月倒数第6天,FRIL表示这个月的最后一个星期五 。
W:只能用在月份中,表示最接近指定天的工作日。
#:只能用在星期中,表示这个月的第几个周几,例如6#3表示这个月的第3个周五。
L:表示last,例如星期中表示7或SAT,月份中表示最后一天31或30,6L表示这个月倒数第6天,FRIL表示这个月的最后一个星期五 。
W:只能用在月份中,表示最接近指定天的工作日。
#:只能用在星期中,表示这个月的第几个周几,例如6#3表示这个月的第3个周五。
说明:这里大家一定要注意哦,上面我们说了有6个域,他们是以空格隔开的,如果举例中有使用符号那就还是一个域。
|