• Spring Boot 定时任务 -- @Scheduled


    Spring Framework 自身提供了对定时任务的支持,本文介绍 Spring Boot 中 @Scheduled 定时器的使用。

    首先,在项目启动类上添加 @EnableScheduling 注解,开启对定时任务的支持

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @SpringBootApplication
    @EnableScheduling
    public class DemoSpringBootScheduledApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoSpringBootScheduledApplication.class, args);
        }
    }
    其次,编写定时任务类和方法,定时任务类通过 Spring IOC 加载,使用 @Component 注解(当然也可以使用 @Controller@Service 等其他与 @Component 作用相同的注解),定时方法使用 @Scheduled 注解。
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    
    @Component
    public class ScheduledTask {
    
        @Scheduled(fixedRate = 3000)//每三秒执行一次
        public void scheduledTask() {
            System.out.println("Task executed at " + LocalDateTime.now());
        }
    }

    注意以上代码使用了 @ScheduledfixedRate 属性,fixedRatelong 类型,表示任务执行的间隔毫秒数,以上代码中的定时任务每 3 秒执行一次。

    运行定时工程,项目启动和运行日志如下,可见每 3 秒打印一次日志执行记录。

    2018-07-25 20:49:29.610  INFO 11060 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Starting DemoSpringBootScheduledApplication on LAPTOP-C375ASPB with PID 11060 (D:JYLDEVIdeaProjectsdemodemo-spring-boot-scheduled	argetclasses started by Ji in D:JYLDEVIdeaProjectsdemo)
    2018-07-25 20:49:29.614  INFO 11060 --- [           main] s.b.s.DemoSpringBootScheduledApplication : No active profile set, falling back to default profiles: default
    2018-07-25 20:49:29.671  INFO 11060 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@345965f2: startup date [Wed Jul 25 20:49:29 CST 2018]; root of context hierarchy
    2018-07-25 20:49:30.749  INFO 11060 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2018-07-25 20:49:30.766  INFO 11060 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
    2018-07-25 20:49:30.791  INFO 11060 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Started DemoSpringBootScheduledApplication in 1.516 seconds (JVM running for 2.051)
    Task executed at 2018-07-25T20:49:30.791
    Task executed at 2018-07-25T20:49:33.780
    Task executed at 2018-07-25T20:49:36.778
    ......

    配置详解查看 @Scheduled 源码(基于 Spring Boot 2.0.3.RELEASE 版本依赖)

    package org.springframework.scheduling.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Repeatable;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Repeatable(Schedules.class)
    public @interface Scheduled {
        String cron() default "";
    
        String zone() default "";
    
        long fixedDelay() default -1L;
    
        String fixedDelayString() default "";
    
        long fixedRate() default -1L;
    
        String fixedRateString() default "";
    
        long initialDelay() default -1L;
    
        String initialDelayString() default "";
    }

    共支持 8 种配置:
    1 cron
    Cron(计划任务)表达式广泛应用于各种定时解决方案,参考 Cron 表达式详解

    2 zone
    用于解析 Cron 表达式的时区

    3 fixedDelay
    上次调用结束和下一次调用结束之间的固定周期(单位:毫秒),即上一次执行完毕时间点之后延迟执行。

    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    
    @Component
    public class ScheduledTask {
    
        @Scheduled(fixedDelay = 3000)
        public void scheduledTask() {
            System.out.println("Task executed at " + LocalDateTime.now());
        }
    }

    运行定时工程,项目启动和运行日志如下,可见每 3 秒打印一次日志执行记录

    2018-07-29 11:08:04.406  INFO 10436 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Starting DemoSpringBootScheduledApplication on LAPTOP-C375ASPB with PID 10436 (D:JYLDEVIdeaProjectsdemodemo-spring-boot-scheduled	argetclasses started by Ji in D:JYLDEVIdeaProjectsdemo)
    2018-07-29 11:08:04.411  INFO 10436 --- [           main] s.b.s.DemoSpringBootScheduledApplication : No active profile set, falling back to default profiles: default
    2018-07-29 11:08:04.468  INFO 10436 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@70b0b186: startup date [Sun Jul 29 11:08:04 CST 2018]; root of context hierarchy
    2018-07-29 11:08:05.517  INFO 10436 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2018-07-29 11:08:05.534  INFO 10436 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
    2018-07-29 11:08:05.568  INFO 10436 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Started DemoSpringBootScheduledApplication in 1.487 seconds (JVM running for 2.045)
    Task executed at 2018-07-29T11:08:05.568
    Task executed at 2018-07-29T11:08:08.598
    Task executed at 2018-07-29T11:08:11.612
    Task executed at 2018-07-29T11:08:14.624
    ...

    4 fixedDelayString
    fixedDelay 作用一样,区别在于 fixedDelaylong 类型,fixedDelayStringString 类型,都是毫秒值。

    5 fixedRate
    以固定周期执行(单位:毫秒)

    6 fixedRateString
    fixedRate 作用一样,区别在于 fixedRatelong 类型,fixedRateStringString 类型,都是毫秒值。

    7 initialDelay
    在第一次执行 fixedRatefixedDelay 任务之前延迟的毫秒数。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    import java.time.LocalDateTime;
    
    @SpringBootApplication
    @EnableScheduling
    public class DemoSpringBootScheduledApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoSpringBootScheduledApplication.class, args);
            // 打印应用启动时间
            System.out.println("App start at " + LocalDateTime.now());
        }
    }
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    
    @Component
    public class ScheduledTask {
    
        @Scheduled(fixedRate = 3000, initialDelay = 5000)
        public void scheduledTask() {
            System.out.println("Task executed at " + LocalDateTime.now());
        }
    }

    运行定时工程,项目启动和运行日志如下,可见应用启动 5 秒后每 3 秒打印一次日志执行记录。

    2018-07-29 11:25:07.564  INFO 1056 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Starting DemoSpringBootScheduledApplication on LAPTOP-C375ASPB with PID 1056 (D:JYLDEVIdeaProjectsdemodemo-spring-boot-scheduled	argetclasses started by Ji in D:JYLDEVIdeaProjectsdemo)
    2018-07-29 11:25:07.568  INFO 1056 --- [           main] s.b.s.DemoSpringBootScheduledApplication : No active profile set, falling back to default profiles: default
    2018-07-29 11:25:07.631  INFO 1056 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@ba8d91c: startup date [Sun Jul 29 11:25:07 CST 2018]; root of context hierarchy
    2018-07-29 11:25:08.736  INFO 1056 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2018-07-29 11:25:08.755  INFO 1056 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
    2018-07-29 11:25:08.774  INFO 1056 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Started DemoSpringBootScheduledApplication in 1.531 seconds (JVM running for 2.074)
    App start at 2018-07-29T11:25:08.785
    Task executed at 2018-07-29T11:25:13.789
    Task executed at 2018-07-29T11:25:16.782
    Task executed at 2018-07-29T11:25:19.781
    ...

    8 initialDelayString
    fixedDelay 作用一样,区别在于 fixedDelaylong 类型,fixedDelayStringString 类型,都是毫秒值。

    注意事项

    1 fixedRatefixedDelay 的区别
    (1) 使用 fixedRate 重写定时任务

    @Scheduled(fixedRate = 3000)
    public void scheduledTask()
        throws InterruptedException {
        System.out.println("Task executed at " + LocalDateTime.now());
        Thread.sleep(10000);
    }

    运行日志如下:

    2018-08-01 21:04:58.911  INFO 9300 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Starting DemoSpringBootScheduledApplication on LAPTOP-C375ASPB with PID 9300 (D:JYLDEVIdeaProjectsdemodemo-spring-boot-scheduled	argetclasses started by Ji in D:JYLDEVIdeaProjectsdemo)
    2018-08-01 21:04:58.920  INFO 9300 --- [           main] s.b.s.DemoSpringBootScheduledApplication : No active profile set, falling back to default profiles: default
    2018-08-01 21:04:59.126  INFO 9300 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4d49af10: startup date [Wed Aug 01 21:04:59 CST 2018]; root of context hierarchy
    2018-08-01 21:05:00.939  INFO 9300 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2018-08-01 21:05:00.967  INFO 9300 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
    2018-08-01 21:05:00.990  INFO 9300 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Started DemoSpringBootScheduledApplication in 2.724 seconds (JVM running for 4.137)
    Task executed at 2018-08-01T21:05:00.996
    Task executed at 2018-08-01T21:05:10.997
    Task executed at 2018-08-01T21:05:21.004
    Task executed at 2018-08-01T21:05:31.009
    ......

    可见,虽然定时任务设置每 3 秒一次,但是因为任务执行过程中会暂停 10 秒,所以后一次任务实际是在前一次任务结束 10 秒后执行的,尽管暂停时间间隔是任务时间间隔的 N 倍,但任务仍只会执行一次。所以定时任务的实际间隔时间变成定时设置时间间隔和任务暂停时间两者中较大的那个。

    (2) 将定时时间间隔设置为 10 秒,任务暂停时间设置为 3 秒,定时任务每 10 秒执行一次(示例代码和运行日志略)

    (3) 使用 fixedDelay 重写定时任务,定时时间间隔设置为 3 秒,任务执行中暂停 10 秒。

    @Scheduled(fixedDelay = 3000)
    public void scheduledTask()
        throws InterruptedException {
        System.out.println("Task executed at " + LocalDateTime.now());
        Thread.sleep(10000);
    }

    运行日志如下:

    2018-08-01 21:20:39.275  INFO 15468 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Starting DemoSpringBootScheduledApplication on LAPTOP-C375ASPB with PID 15468 (D:JYLDEVIdeaProjectsdemodemo-spring-boot-scheduled	argetclasses started by Ji in D:JYLDEVIdeaProjectsdemo)
    2018-08-01 21:20:39.279  INFO 15468 --- [           main] s.b.s.DemoSpringBootScheduledApplication : No active profile set, falling back to default profiles: default
    2018-08-01 21:20:39.340  INFO 15468 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@525b461a: startup date [Wed Aug 01 21:20:39 CST 2018]; root of context hierarchy
    2018-08-01 21:20:40.498  INFO 15468 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2018-08-01 21:20:40.523  INFO 15468 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
    2018-08-01 21:20:40.538  INFO 15468 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Started DemoSpringBootScheduledApplication in 1.627 seconds (JVM running for 2.174)
    Task executed at 2018-08-01T21:20:40.542
    Task executed at 2018-08-01T21:20:53.562
    Task executed at 2018-08-01T21:21:06.569
    Task executed at 2018-08-01T21:21:19.578
    Task executed at 2018-08-01T21:21:32.604
    Task executed at 2018-08-01T21:21:45.625
    Task executed at 2018-08-01T21:21:58.637
    ......

    从日志中可以看出,除前两次任务实际间隔时间为 7 秒(10 - 3)外,后续任务间隔时间都是 13 秒。

    (4) 将定时任务时间间隔设置为 10 秒,任务执行过程中暂停 3 秒,运行日志如下:

    2018-08-01 21:27:01.442  INFO 14060 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Starting DemoSpringBootScheduledApplication on LAPTOP-C375ASPB with PID 14060 (D:JYLDEVIdeaProjectsdemodemo-spring-boot-scheduled	argetclasses started by Ji in D:JYLDEVIdeaProjectsdemo)
    2018-08-01 21:27:01.446  INFO 14060 --- [           main] s.b.s.DemoSpringBootScheduledApplication : No active profile set, falling back to default profiles: default
    2018-08-01 21:27:01.509  INFO 14060 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@61d47554: startup date [Wed Aug 01 21:27:01 CST 2018]; root of context hierarchy
    2018-08-01 21:27:02.633  INFO 14060 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
    2018-08-01 21:27:02.651  INFO 14060 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
    2018-08-01 21:27:02.670  INFO 14060 --- [           main] s.b.s.DemoSpringBootScheduledApplication : Started DemoSpringBootScheduledApplication in 1.577 seconds (JVM running for 2.208)
    Task executed at 2018-08-01T21:27:02.670
    Task executed at 2018-08-01T21:27:15.675
    Task executed at 2018-08-01T21:27:28.704
    Task executed at 2018-08-01T21:27:41.713
    Task executed at 2018-08-01T21:27:54.727
    ......

    任务时间间隔变成了 13 秒(10 + 3)
    从以上运行日志中可以看出 fixedRatefixedDelay 的区别。

    2 cronfixedRatefixedDelay 不能共存,否则会出现以下运行期异常

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scheduledTask' defined in file [...demodemo-spring-boot-scheduled	argetclassesdemospringootscheduledScheduledTask.class]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Encountered invalid @Scheduled method 'scheduledTask': Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required
    除本文中介绍的定时任务解决方案外,还有另外两种方法实现定时任务:
    (1) 使用 java.util.Timerjava.util.TimerTask 这些 Java 原生 API,优点是简单快捷,不需要添加额外的依赖,但这些原生 API 本身也存在缺陷;
    (2) 集成 QuartzElastic-Job 这些定时框架,优点是功能强大,更适合产品化应用,缺点是较重。
  • 相关阅读:
    Maximum Depth of Binary Tree
    Single Number
    Merge Two Sorted Lists
    Remove Nth Node From End of List
    Remove Element
    Remove Duplicates from Sorted List
    Add Two Numbers
    编译视频直播点播平台EasyDSS数据排序使用Go 语言 slice 类型排序的实现介绍
    RTMP协议视频直播点播平台EasyDSS在Linux系统中以服务启动报错can’t evaluate field RootPath in type*struct排查
    【解决方案】5G时代RTMP推流服务器/互联网直播点播平台EasyDSS实现360°全景摄像机VR直播
  • 原文地址:https://www.cnblogs.com/zouhong/p/14219989.html
Copyright © 2020-2023  润新知