spring boot 定时任务

168 阅读4分钟
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
spring boot 定时任务

定时任务在我们的系统中有着很重要的作用,对于那些没有实时性要求,并且需要周期性重复执行的任务来说,使用定时任务既可以解决。

业务场景

当我们在 12306 提交车票订单后不支付,返回订单页面,你会发现一个三十分钟的倒计时,三十分钟内未支付自动取消订单,车票将自动回到票池中,等待他人购买。

淘宝购物后,如果用户不主动确认收货的话,系统会在一段时间以后自动确认收货。

还有吃瓜群众最喜欢的微博热搜,也会定时去汇总热搜词条,更新热搜榜

在指定的时间,按照指定的频率(或执行次数)自动的执行指定的任务。

java 中的定时任务

单机

Timer:来自 JDK,从 JDK 1.3 开始引入。JDK 自带,不需要引入外部依赖,简单易用,当然功能相对单一

ScheduledExecutorService:同样来自 JDK,比 Timer 要晚一些,JDK 1.5 才引入,它的引入弥补了 Timer 的一些缺陷;

Spring Task:看名字就知道来自 Spring,Spring 环境中单机定时任务的不二之选。

分布式

Quartz:分布式定时任务的基石(其本身并不支持分布式任务调度)。功能丰富且强大,即能与简单的单体应用结合,又能支撑起复杂的分布式系统;

Elastic-job:来自当当网,基于 Quartz 开发,是一个具有完整定时任务处理流程,并且支持分布式的定时任务调度解决方案;

xxl-job:来自大众点评,同样也是基于 Quartz 开发,是一个轻量级的分布式任务调度平台。简单易用,国内使用很广泛。

另外,唯品会也有一个定时任务平台 ——Saturn,是对 Elastic-job 进行的二次开发。

通过上面的介绍,我们知道这些分布式的定时任务平台,都是基于 Quartz 的基础上进行的扩展。Quartz 算得上是 Java 定时任务届的标准了。

Spring Boot 整合定时任务

选择 Spring Task 与 Spring Boot 结合来实现一个定时任务的小实例。

在 Spring Boot 中使用定时任务,与使用其他技术一样,还是一如既往的简单方便。要开始定时任务功能,我们需要用到三个注解 ——@EnableScheduling、@Scheduled 和 @Component。

@EnableScheduling 用来开启定时任务功能,放在工程的主类上;@Scheduled 用来设定任务的执行规则,放在具体的定时任务方法上; @Component 我们已经很熟悉了,就是将类标记为一个被 Spring 管理的功能组件,放在包含有定时任务方法的类上。

Spring Task 有三种模式,分别是:fixedDelay、cron 和 fixedRate。话不多说,我们先看代码:

@Slf4j
@Component
public class TimeTask {

    private int[] people = {9000,2000,3000,1000};
    
    private int count = 0;
    
    @Scheduled(fixedDelay = 5000)
    public void fixedDelayTask() throws InterruptedException {
        if (count < 4) {
            int timeConsuming = people[count];
            log.info("fixedDelayTask-----第 {} 个任务开始处理,耗时:{}ms",count+1, timeConsuming);
            Thread.sleep(timeConsuming);
            count++;
        }
    }
    
    @Scheduled(cron = "0/5 * * * * ? ")
    public void cronTask() throws InterruptedException {
        if (count < 4) {
            int timeConsuming = people[count];
            log.info("cronTask-----第 {} 个任务开始处理,耗时:{}ms",count+1, timeConsuming);
            Thread.sleep(timeConsuming);
            count++;
        }
    }
    
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() throws InterruptedException {
        if (count < 4) {
            int timeConsuming = people[count];
            log.info("fixedRateTask-----第 {} 个任务开始处理,耗时:{}ms",count+1, timeConsuming);
            Thread.sleep(timeConsuming);
            count++;
        }
    }

}

Cron 表达式

以上三种模式中,cron 模式最为灵活,可以应对更多的情况。下面简单介绍一下 cron 表达式,一个 cron 表达式总共有 7 个元素,分别如下:

时间单位是否必填取值范围通配符
0-59 的整数, - * / 四个字符
0-59 的整数, - * / 四个字符
0-23 的整数, - * / 四个字符
1-31 的整数(需要考虑该月的具体天数),- * ? / L W C 八个字符
1~12 的整数或者 JAN-DEC, - * / 四个字符
1~7 的整数或者 SUN-SAT (1=SUN), - * ? / L C # 八个字符
1970~2099, - * / 四个字符

表达式的规则不需要刻意去记,需要的时候使用借助图形化工具生成即可 ——cron 生成器。

总结

这种单机版的定时任务适合简单的任务处理,当我们需要处理更多更复杂的任务时,就需要借助文章中提到的分布式定时任务调度。