Spring Boot系列之使用@Scheduled实现定时任务

简介: 假设,我们有一个数据同步的需求:每隔5秒执行一次数据同步。那么我们该如何实现这个数据同步任务呢?

假设,我们有一个数据同步的需求:每隔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

spring-boot-scheduled-cron.png

先看一个例子:每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-framework/docs/current/reference/html/integration.html#scheduling-cron-expression

spring-boot-scheduled-cron-examples.png

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

L,表示最后,比如一月最后一个星期天。

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

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

3、Macros

spring-boot-scheduled-cron-macros.png

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

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

spring-boot-scheduled-yml-no-tip.png

发现问题了吗?

我们在写配置的时候,没有提示,并且这种看上去,也不友好。

那要怎么解决呢?

先引入依赖:

<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 这个了吗?

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

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

最后,再来看看吧。

spring-boot-scheduled-yml-tip.png

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

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

目录
相关文章
|
3月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
定时任务在企业应用中至关重要,常用于异步数据处理、自动化运维等场景。在单体应用中,利用Java的`java.util.Timer`或Spring的`@Scheduled`即可轻松实现。然而,进入微服务架构后,任务可能因多节点并发执行而重复。Spring Cloud Alibaba为此发布了Scheduling模块,提供轻量级、高可用的分布式定时任务解决方案,支持防重复执行、分片运行等功能,并可通过`spring-cloud-starter-alibaba-schedulerx`快速集成。用户可选择基于阿里云SchedulerX托管服务或采用本地开源方案(如ShedLock)
129 1
|
13天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
25 2
|
1月前
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
56 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
1月前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
139 1
|
1月前
|
Java 调度 开发者
spring的@Scheduled()有几种定时模式?
【10月更文挑战第12天】spring的@Scheduled()有几种定时模式?
88 1
|
1月前
|
存储 Java API
简单两步,Spring Boot 写死的定时任务也能动态设置:技术干货分享
【10月更文挑战第4天】在Spring Boot开发中,定时任务通常通过@Scheduled注解来实现,这种方式简单直接,但存在一个显著的限制:任务的执行时间或频率在编译时就已经确定,无法在运行时动态调整。然而,在实际工作中,我们往往需要根据业务需求或外部条件的变化来动态调整定时任务的执行计划。本文将分享一个简单两步的解决方案,让你的Spring Boot应用中的定时任务也能动态设置,从而满足更灵活的业务需求。
100 4
|
1月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
64 2
|
4月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
14979 29
|
3月前
|
Java 开发者 Spring
Spring Boot实战宝典:揭秘定时任务的幕后英雄,让业务处理如流水般顺畅,轻松驾驭时间管理艺术!
【8月更文挑战第29天】在现代应用开发中,定时任务如数据备份、报告生成等至关重要。Spring Boot作为流行的Java框架,凭借其强大的集成能力和简洁的配置方式,为开发者提供了高效的定时任务解决方案。本文详细介绍了如何在Spring Boot项目中启用定时任务支持、编写定时任务方法,并通过实战案例展示了其在业务场景中的应用,同时提供了注意事项以确保任务的正确执行。
53 0
|
3月前
|
Dubbo Java 调度
揭秘!Spring Cloud Alibaba的超级力量——如何轻松驾驭分布式定时任务调度?
【8月更文挑战第20天】在现代微服务架构中,Spring Cloud Alibaba通过集成分布式定时任务调度功能解决了一致性和可靠性挑战。它利用TimerX实现任务的分布式编排与调度,并通过`@SchedulerLock`确保任务不被重复执行。示例代码展示了如何配置定时任务及其分布式锁,以实现每5秒仅由一个节点执行任务,适合构建高可用的微服务系统。
70 0
下一篇
无影云桌面