项目亮点之定时任务
后台定时任务
后台定时作业是实际项目中经常要用到的,例如每5分钟跑一次新下的订单并发送邮件等等,实际使用非常多。
后台作业类
@Component
public class ScheduledExample {
// @Scheduled(fixedRate = 5000)
// 上一次开始执行时间点之后5秒再执行
public void job1() {
System.out.println(Thread.currentThread() + " now is " + LocalTime.now());
}
// @Scheduled(fixedDelay = 5000)
// 上一次执行完毕时间点之后5秒再执行
public void job2() {
System.out.println(Thread.currentThread() + " now is " + LocalTime.now());
}
// @Scheduled(initialDelay = 1000, fixedRate = 5000)
// 第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
public void job3() {
System.out.println( Thread.currentThread() + " now is " + LocalTime.now());
}
//@Scheduled(cron = "0/3 * * * * ?")
// cron表达式
public void job4() {
System.out.println( Thread.currentThread() + " now is " + LocalTime.now());
}
}
启动类
@SpringBootApplication
@EnableScheduling
@MapperScan("com.bmw.search.dao")
public class SearchApplication {
public static void main(String[] args) {
SpringApplication.run(SearchApplication.class, args);
}
}
cron表达式
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式:
1.Seconds Minutes Hours DayofMonth Month DayofWeek Year
2.Seconds Minutes Hours DayofMonth Month DayofWeek
每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
*:表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。
?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和 DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。
L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
举例:
每隔5秒执行一次:"*/5 * * * * ?"
每隔1分钟执行一次:"0 */1 * * * ?"
每天23点执行一次:"0 0 23 * * ?"
每天凌晨1点执行一次:"0 0 1 * * ?"
每月1号凌晨1点执行一次:"0 0 1 1 * ?"
每天的0点、13点、18点、21点都执行一次:"0 0 0,13,18,21 * * ?"
防止重复启动
@Scheduled定时任务会在上次任务结束时再执行第二次任务,如果第二次任务堵在哪里了,时间会顺延 。
如果担心实际项目启动重复了,比如错误部署了集群,可以采用锁的机制,这样在项目启动的时候在redis中设置锁,执行完毕或者出异常了在finally中把锁进行删除
如果没有锁的机制,代码结构为:
try {
//实际的真实任务
}catch(Exception ex) {
log.error("",ex);//必须有异常捕获机制,否则的话代码内部抛出了RuntimeException,没有扑获的话任务会异常解除,并且没有错误日志,无法进行跟踪
}
如果采用了上面说的用锁来防止重复机制(一般不需要),代码结构如下:
try {
//首先是获取锁,如果获取失败,打印log日志,直接返回
//实际的真正任务
} catch(Exception ex) {
//错误日志打印log日志,跟上面的一样,必须有异常捕获机制
} finally {
//释放锁,否则的话下次将不能再正常运行
}