Spring定时任务—Spring Task

335 阅读5分钟

了解Spring Task之前,我们先了解一下什么是定时任务。

1. 定时任务

定时任务其实听见这个大家都知道什么意思,日常中大家经常的用到手机闹钟,这就是一个定时任务,还有一些其他的应用场景:

  • 定时清除系统垃圾
  • 定时发送节日祝贺信息
  • 定时处理未支付订单

定时任务的应用场景是非常广泛的。定时任务就是系统在特定的时间执行一段代码。在java中,定时任务的主要实现方式有以下三种:

  • Java自带的java.util.Timer类,这个类允许调度一个java.util.TimerTask任务。使用这种方式可以让程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
  • SpringTask: spring自主研发的任务调度工具,并且存在于Spring体系中,可以按照约定的时间自动执行某个代码逻辑。不需要添加任何依赖。
  • Quartz:这是一个功能比较强大的开源任务调度服务,几乎可以集成到任务Java应用程序中,可以让程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。

2. cron表达式

这个表达式其实就是一个字符串,Spring Task就是依靠cron表达式定义任务触发的时间。熟悉Linux系统应该对此有所涉及,在linux设置定时任务时也是根据cron表达式来的。

构成规则:分为6或7个域,每一个域代表一个含义,由空格隔开。

每个域代表的含义分别为:秒、分钟、小时、日、月、周、年(可选)

即两种语法格式:

  1. Seconds Minutes Hours DayofMonth Month DayofWeek Year
  2. Seconds Minutes Hours DayofMonth Month DayofWeek

特数字符:

(1) * 表示匹配该域的任意值。假如在Minutes域使用 *,即表示每分钟都会触发事件。

(2) ? 表示未说明的值,即不关心它为何值;一般用在DayofMonth和DayofWeek两个域。因为DayofMonth和DayofWeek会相互影响。如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法:* * * 20 * ?,其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。

(3) - 表示一个指定的范围;如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次

(4) , 表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。

(5) / 表示起始时间开始触发,然后每隔固定时间触发一次,符号前表示开始时间,符号后表示每次递增的值。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.

(6) L 表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。

(7) W 表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。

(8) LW 这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。

(9) # 用于确定每个月第几个星期几,#前面代表星期几,#后面代表一个月的第几周,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。(这里周天是第一周的开始,即周天是1)

cron表达式案例:

*/5 * * * * ?每隔5秒执行一次
0 */1 * * * ?每隔1分钟执行一次
0 0 5-15 * * ?每天5-15点整点触发
0 0/3 * * * ?每三分钟触发一次
0 0-5 14 * * ?在每天下午2点到下午2:05期间的每1分钟触发
0 0/5 14 * * ?在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ?在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0/30 9-17 * * ?朝九晚五工作时间内每半小时
0 0 10,14,16 * * ?每天上午10点,下午2点,4点

若不熟悉该表达的使用也没有关系,这里推荐一个网站,可以根据相关设定生成cron表达式。

在线Cron表达式生成器 (qqe2.com)

3. Spring Task案例

介绍完相关知识,还是需要案例来试试Spring Task的具体效果。这个是无需导入依赖的,Spring自身集成的

首先创建一个Spring Boot的项目,在启动类开启定时任务。 也就是在启动类上方添加@EnableScheduling注解即可开启定时任务,代码如下:

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.scheduling.annotation.EnableScheduling;
 ​
 @SpringBootApplication
 @EnableScheduling // 开启定时任务
 public class SpringTaskApplication {
 ​
     public static void main(String[] args) {
         SpringApplication.run(SpringTaskApplication.class, args);
     }
 ​
 }

然后编写一个定时任务类,一般来说,都习惯于新建一个task的包来管理定时任务。

image-20240317153000955

 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 ​
 import java.text.SimpleDateFormat;
 import java.util.Date;
 ​
 // 必须将该类注入到Spring容器中
 @Component
 public class MyTask {
 ​
     @Scheduled(cron = "* * * * * *") // 定时任务方法,每秒执行一次
     public void task() {
         SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
         System.out.println(sdf.format(new Date()));
     }
 }

recording

@Scheduled写在方法上方,指定该方法定时执行。常用参数如下:

  1. cron:cron表达式,定义方法执行的时间规则。
  2. fixedDelay:固定间隔时间,表示上一任务完成后间隔多少秒再执行。单位为毫秒
  3. fixedRate:表示每间隔多少秒执行一次任务,但是如果该事件内任务没有执行完,会在任务执行结束后,立即执行任务,然而不会任务没有结束前,就开始下次一任务。单位是毫秒。
  4. initialDelay: 固定等待时间,启动时间开始,项目启动后不马上执行定时器,根据initialDelay的值延时执行

后面三个参数大家可以自行尝试。