关于springboot:Spring-Boot系列之使用Scheduled实现定时任务

2次阅读

共计 5227 个字符,预计需要花费 14 分钟才能阅读完成。

假如,咱们有一个数据同步的需要:每隔 5 秒执行一次数据同步。那么咱们该如何实现这个数据同步工作呢?

哈喽,大家好,我是小冯。

明天给分享在 Spring Boot 我的项目中应用 @Scheduled 实现定时工作。

疾速开始

咱们就下面的需要,基于 Spring Boot 框架,搭建一个简略的数据同步调度工作。

Demo 如下。

创立工程

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

因为咱们是基于 Spring Boot 开发,所以不须要其余依赖。

package com.fengwenyi.demospringbootscheduled;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author <a href="https://www.fengwenyi.com">Erwin Feng</a>
 * @since 2021-09-29
 */
@SpringBootApplication
public class DemoSpringBootScheduledApplication {public static void main(String[] args) {SpringApplication.run(DemoSpringBootScheduledApplication.class, args);
    }

}

启用调度注解

package com.fengwenyi.demospringbootscheduled.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
 * @author <a href="https://www.fengwenyi.com">Erwin Feng</a>
 * @since 2021-09-29
 */
@Configuration
@EnableScheduling
public class ScheduledConfiguration {}

数据同步工作

package com.fengwenyi.demospringbootscheduled.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author <a href="https://www.fengwenyi.com">Erwin Feng</a>
 * @since 2021-10-21
 */
@Component
@Slf4j
public class DemoTask {@Scheduled(initialDelay = 5, fixedRate = 5, timeUnit = TimeUnit.SECONDS)
    public void dataSynchronizationTask() {log.info("开始执行数据同步工作");
    }

}

执行

通过意思步骤,咱们的 demo 就搭建好了,跑一下,控制台打印日志如下:

2021-10-21 21:44:55.711  INFO 10320 --- [scheduling-1] c.f.d.task.DemoTask                      : 开始执行数据同步工作
2021-10-21 21:45:00.705  INFO 10320 --- [scheduling-1] c.f.d.task.DemoTask                      : 开始执行数据同步工作
2021-10-21 21:45:05.715  INFO 10320 --- [scheduling-1] c.f.d.task.DemoTask                      : 开始执行数据同步工作
2021-10-21 21:45:10.710  INFO 10320 --- [scheduling-1] c.f.d.task.DemoTask                      : 开始执行数据同步工作 

通过打印日志,咱们指定,没距离 5 秒,就会主动执行“数据同步工作”,这样就简略实现了任务调度。

@Scheduled 参数详解

上面咱们对 @Scheduled 注解提供配置,做一个阐明。

cron

先看一个例子:每 5 秒执行一次工作。

@Scheduled(cron = "0/5 * * * * ?")
public void testCron01() {log.info("test cron 01 exec");
}

执行:

2021-10-23 02:31:50.030  INFO 18872 --- [scheduling-1] c.f.d.task.ScheduledTask                 : test cron 1 exec
2021-10-23 02:31:55.009  INFO 18872 --- [scheduling-1] c.f.d.task.ScheduledTask                 : test cron 1 exec
2021-10-23 02:32:00.005  INFO 18872 --- [scheduling-1] c.f.d.task.ScheduledTask                 : test cron 1 exec

对于 cron 表达式,上面要做几点阐明:

1、构造

 ┌───────────── second (0-59)
 │ ┌───────────── minute (0 - 59)
 │ │ ┌───────────── hour (0 - 23)
 │ │ │ ┌───────────── day of the month (1 - 31)
 │ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC)
 │ │ │ │ │ ┌───────────── day of the week (0 - 7)
 │ │ │ │ │ │          (0 or 7 is Sunday, or MON-SUN)
 │ │ │ │ │ │
 * * * * * *

spring 反对的 cron 表达式,由 6 位形成,别离示意:

  • 分钟
  • 小时
  • 天(月)
  • 天(星期)

2、Cron 表达式示例

通过浏览一些 cron 示例,更能了解 cron 表达式的具体含意,咱们就以 spring 官网文档中的示例进行学习。

官网文档:https://docs.spring.io/spring…

星号(*)和问号(?)都示意通配符,其中,? 能够用在 天(月) 天(星期) 上,即第 4 位和第 6 位。

L,示意最初,比方一月最初一个星期天。

W,示意工作日(周一到周五)。

#,示意每月中的第几个星期几。5#2:示意每月第 2 个星期五。MON#1:示意每月第 1 个星期一。

3、Macros

spring 为咱们提供了几个特地的 cron 表达式(整年,整月,整周,终日或者整夜,整小时),咱们能够间接用。

@Scheduled(cron = "@hourly")
public void testCron02() {log.info("test cron 02 exec");
}

zone

时区

fixedDelay

固定距离,参数类型为 long。

fixedDelayString

固定距离,参数类型为 String,同 fixedDelay。

fixedRate

固定速率,参数类型为 long。

fixedRateString

固定速率,参数类型为 long,同 fixedRate。

timeUnit

工夫单位,从 5.3.10 开始

spring boot 2.5.5 开始

initialDelay

第一次延时工夫,参数类型为 long。

initialDelayString

第一次延时工夫,参数类型为 String。

fixedDelay 与 fixedRate

区别

fixedDelay,间隔时间,以工作完结工夫算起。

fixedRate,间隔时间,以工作开始工夫算起。

间隔时间大于工作执行工夫

比方一个工作,间隔时间为 5 秒,工作执行工夫是 2 秒。

假如 fixedDelay 在第 5 秒执行第一次,那么第二次会在 12 秒执行。

而 fixedRate 在第 5 秒执行第一次,那么第二次会在 10 秒执行。

间隔时间小于工作执行工夫

比方一个工作,间隔时间为 2 秒,工作执行工夫是 5 秒。

假如 fixedDelay 在第 2 秒执行第一次,那么第二次会在 9 秒执行。

而 fixedRate 在第 2 秒执行第一次,那么第二次会在 7 秒执行。

配置文件

在理论我的项目中,执行工夫个别写在配置文件中,不便批改,不然,如果要批改,还要改代码。

对于如何写在配置文件中,置信你肯定遇到过这个问题。

这部分咱们解决这样一个问题,并进行总结。

cron

@Scheduled(cron = "${erwin.cron:0/2 * * * * ?}")
public void cronTaskYmlDemo() {log.info("cron yml demo");
}

配置:

erwin:
  cron: 0/10 * * * * ?

如果配置文件没有配,就会应用默认的值。

请留神,值为空,不等于没有配。

fixedDelay

在下面参数解释的时候,咱们指定,这个接管的是一个整数,那该如何将解决这个问题。

置信聪慧的你,肯定也是猜到了。

对,没错,就是它。

@Scheduled(initialDelay = 5, fixedDelayString = "${erwin.fixed-delay:2}", timeUnit = TimeUnit.SECONDS)
public void fixedDelayTaskYmlDemo() {log.info("fixedDelay yml demo");
}

配置:

erwin:
  fixed-delay: 5

简略解释一下,如果在配置文件中没有配置,则每隔 2 秒执行一次,如果配置了,就每隔 5 秒执行一次。initialDelay 示意,我的项目启动后,5 秒开始执行第一次工作。

值得注意的是,${erwin.fixed-delay:2},冒号前后不能有空格。

fixedRate

有了下面的教训,置信你肯定学会了。咱们一起来看示例吧。

@Scheduled(initialDelay = 5, fixedRateString = "${erwin.fixed-rate:2}", timeUnit = TimeUnit.SECONDS)
public void fixedRateTaskYmlDemo() {log.info("fixedRate yml demo");
}

配置:

erwin:
  fixed-rate: 5

执行示例:

2021-10-25 20:41:57.394  INFO 19368 --- [scheduling-1] c.f.d.task.DemoTask                      : fixedRate yml demo
2021-10-25 20:41:59.394  INFO 19368 --- [scheduling-1] c.f.d.task.DemoTask                      : fixedRate yml demo
2021-10-25 20:42:01.394  INFO 19368 --- [scheduling-1] c.f.d.task.DemoTask                      : fixedRate yml demo

最初的最初,还有一个问题,先看图。

发现问题了吗?

咱们在写配置的时候,没有提醒,并且这种看上去,也不敌对。

那要怎么解决呢?

先引入依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

咱们无妨写一个属性配置类。

@Getter
@Setter
@Configuration
@ConfigurationProperties("erwin")
public class ErwinProperties {

    private String cron;

    private Long fixedDelay;

    private Long fixedRate;

}

你留神到 erwin 这个了吗?

刚开始写示例的时候,你是不是很好奇,为什么会有这个前缀

哈哈,其实咱们早已埋下了伏笔。

最初,再来看看吧。

同时,这时候,你再写配的时候,就会有提醒了。

明天分享的内容,就是这些了,咱们下期再见!

正文完
 0