zoukankan      html  css  js  c++  java
  • 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 这些定时框架,优点是功能强大,更适合产品化应用,缺点是较重。
  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/zouhong/p/14219989.html
Copyright © 2011-2022 走看看