前言
在开发中,我们会有定时执行某些任务的需求,例如定时清理过期文件、定时发送邮件等等。SpringBoot 为我们提供了便捷的方式来配置定时任务,只需要打上几个注解即可。那么下面让我们来看看 SpringBoot 中如何开发定时任务。
开启定时任务
想要使用定时任务,需先打开定时任务开关。
在入口类中添加 @EnableScheduling
注解
1 2 3 4 5 6 7
| @SpringBootApplication @EnableScheduling public class SchedulerTaskApplication { public static void main(String[] args) { SpringApplication.run(SchedulerTaskApplication.class, args); } }
|
使用 @Scheduled 配置定时任务
配置定时任务非常简单,只需要在需要定时执行的方法上添加 @Scheduled
注解即可。注意,该类上需要打上组件型注解,例如 @Componet
,这样该类才会被注入到 Spring 容器中进行管理,@Scheduled
才会生效。例如:
1 2 3 4 5 6 7 8 9 10 11 12
| @Component public class SchedulerTask1 { private static final Logger LOG = LoggerFactory.getLogger(SchedulerTask1.class);
@Scheduled(cron = "* * * * * ?") public void scheduler1() { LOG.info("scheduler1 测试: " + System.currentTimeMillis()); } }
|
运行程序,结果如下:
1 2 3 4 5 6 7 8
| 2020-06-19 00:28:06.002 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497686002 2020-06-19 00:28:07.003 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497687003 2020-06-19 00:28:08.002 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497688002 2020-06-19 00:28:09.002 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497689002 2020-06-19 00:28:10.001 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497690001 2020-06-19 00:28:11.001 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497691001 2020-06-19 00:28:12.005 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497692005 2020-06-19 00:28:13.001 INFO 12744 --- [ scheduling-1] c.i.s.r.scheduler.SchedulerTask : scheduler1 测试: 1592497693001
|
可以看到,日志每秒钟打印一次,这说明该方法每秒钟被执行一次。
@Scheduled 注解参数说明
@Scheduled
支持多种定时规则进行配置。
- cron:
cron
表达式是 Linux 中定时任务的配置规则。具体使用方式可以参考 cron。文末也附上了一些配置示例,方便大家参考。
- zone: 时区。默认为服务器所在时区,接收类型为
java.util.TimeZone
。
- fixedDelay / fixedDelayString: 表示在上次执行之后多久后再次执行。它俩的区别为前者类型为
long
类型,后者为 String
,单位均为 ms。
- fixedRate / fixedRateString: 表示在上次执行开始之后多久后再次执行。同样,它俩的区别也仅为参数类型的区别。
- initialDelay / initialDelayString: 表示第一次任务执行延迟多久,区别同上。
@Scheduled 的多线程使用
@Scheduled
默认是单线程执行的,多个 @Scheduled
任务都用的同一个线程。如果某个任务是个耗时的操作,那么其它定时任务都会因为这一个耗时的任务而堵塞。
例如,两个定时任务 A、B 都是每秒触发一次。如果任务 A 执行一次需要耗时 5 秒,则任务 A、B 都要等任务 A 执行后才能再执行,这就达不到任务 A、B 每秒执行一次的效果了。
那么,如何能让每个定时任务按照配置好的定时规则准时执行呢?这就需要我们将定时任务配置成多线程的方式。
在入口类中添加 @EnableAsync
,开启异步执行。在定时任务上添加 @Async
注解,标识该方法异步执行。方法中我们通过 sleep
来模拟耗时操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Component public class SchedulerTask2 { private static final Logger LOG = LoggerFactory.getLogger(SchedulerTask2.class);
@Async @Scheduled(cron = "* * * * * ?") public void scheduler1() { LOG.info("SchedulerTask2 scheduler1 执行: " + System.currentTimeMillis()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } LOG.info("SchedulerTask2 scheduler1 执行完了: " + System.currentTimeMillis()); } }
|
运行程序我们可以看到:
1 2 3 4 5 6 7 8 9 10 11 12
| 2020-06-19 01:13:04.011 INFO 13495 --- [ task-1] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500384011 2020-06-19 01:13:05.002 INFO 13495 --- [ task-2] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500385002 2020-06-19 01:13:06.002 INFO 13495 --- [ task-3] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500386001 2020-06-19 01:13:07.005 INFO 13495 --- [ task-4] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500387004 2020-06-19 01:13:08.003 INFO 13495 --- [ task-5] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500388003 2020-06-19 01:13:09.003 INFO 13495 --- [ task-6] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500389003 2020-06-19 01:13:09.013 INFO 13495 --- [ task-1] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行完了: 1592500389013 2020-06-19 01:13:10.004 INFO 13495 --- [ task-2] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行完了: 1592500390004 2020-06-19 01:13:10.004 INFO 13495 --- [ task-7] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500390004 2020-06-19 01:13:11.002 INFO 13495 --- [ task-3] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行完了: 1592500391002 2020-06-19 01:13:11.003 INFO 13495 --- [ task-8] c.i.s.r.scheduler.SchedulerTask2 : SchedulerTask2 scheduler1 执行: 1592500391003
|
虽然方法执行需要耗时 5 秒,但是每个任务还是按照每秒钟触发一次准时执行了。通过前面的 task-n 可以看出,每个任务的执行都使用了不同的线程。
@Async
默认线程池个数为 8 个,我们也可以通过配置来满足不同场景的需要。有关 @Async
多线程的使用,我会在后续的章节为大家介绍。
以上就是 SpringBoot 定时任务的使用方法。
附1:Cron 表达式示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 0 0 2 1 * ? * 表示在每月的1日的凌晨2点调度任务 0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业 0 15 10 ? * 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作 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 15 10 * * ? * 每天上午10:15触发 0 15 10 * * ? 2005 2005年的每天上午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触发 0 15 10 L * ? 每月最后一日的上午10:15触发 0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发 0 15 10 ? * 6L 2002-2005 002年至2005年的每月的最后一个星期五上午10:15触发 0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
|
本章代码:GitHub
我是因特马,一个爱分享的斜杠程序员~
欢迎关注我的公众号:因特马
