SpringBoot中定时任务入门(@Scheduled )详解

简介: SpringBoot中定时任务入门(@Scheduled )详解

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor 、TaskScheduler 接口。

SpringBoot中使用两个注解:@EnableScheduling、@Scheduled来简单实现定时任务。

【1】@Scheduled注解

按照惯例,先看javadoc源码:

  • 使一个方法定时被执行的注解。其属性cron/fixedDelay/fixedRate必须有一个被指定
  • 该注解标记的方法没有参数,也没有返回值。即使写了返回值,也会被忽略。
  • 该注解被ScheduledAnnotationBeanPostProcessor处理器解析。
  • 可以手动注册该bean,当然更方便的是使用<task:annotation-driven/>配置或者@EnableScheduling注解。

这个注解可以用来作为一个meta-annotation通过属性覆盖去创建自定义的组合注解。

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {
//   cron表达式
  String cron() default "";
//corn表达式的时区,默认为空,使用服务器的local time zone。
  String zone() default "";
//  周期为在最后一次调用结束和下一次调用开始,以毫秒为单位,固定周期地执行注释的方法。
  long fixedDelay() default -1;
//周期间隔为在最后一次调用结束和下一次调用开始,以毫秒为单位,固定周期地执行注释的方法。
  String fixedDelayString() default "";
//固定周期地执行注解方法,周期为调用间隔,单位为毫秒
  long fixedRate() default -1;
  String fixedRateString() default "";
//   fixedRate() 或fixedDelay()第一次执行前延迟的毫秒数
  long initialDelay() default -1;
//   fixedRate() 或fixedDelay()第一次执行前延迟的毫秒数
  String initialDelayString() default "";
}

【2】@EnableScheduling 注解

启动Spring的定时任务执行能力,通常用在配置类上面,类似于xml片段<task:*>

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}

该注解会使Spring 容器中所有bean中的@Scheduled注解起作用。如下所示,给定一个类MyTask :

package com.myco.tasks;
public class MyTask {
// 每1000ms 执行一次该方法
    @Scheduled(fixedRate=1000)
    public void work() {
        // task execution logic
    }
}

如下配置确保MyTask.work()每1000ms被调用一次。

@Configuration
@EnableScheduling
public class AppConfig {
    @Bean
    public MyTask task() {
        return new MyTask();
    }
}

如果MyTask使用了注解@Component,下面的配置将会确保其@Scheduled标注的方法会被以期望的间隔进行调用。

 @Configuration
 @EnableScheduling
 @ComponentScan(basePackages="com.myco.tasks")
 public class AppConfig {
 }

甚至可以直接在配置类中写@Scheduled注解标注的方法。

@Configuration
@EnableScheduling
public class AppConfig {
 *
    @Scheduled(fixedRate=1000)
    public void work() {
        // task execution logic
    }
}

默认,将会寻找一个相关联的scheduler ,可能是上下文中一个唯一的TaskScheduler或者一个bean id为taskScheduler。ScheduledExecutorService也将执行同样的查找。如果上面两个定时任务处理器都没有被找到,一个本地单线程默认scheduler 将会被创建并被注册器使用。

如果想获得更多的控制,配置类应该实现SchedulingConfigurer接口。这将可以获取底层的ScheduledTaskRegistrar实例。

下面的例子演示了如何自定义Executor去执行定时任务。

@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }
    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}

注意上面例子中@Bean(destroyMethod="shutdown")的使用。这将确保线程任务执行器在Spring容器被销毁时正确的关闭。实现SchedulingConfigurer还可以通过ScheduledTaskRegistrar对任务注册实细粒度

 @Configuration
 @EnableScheduling
 public class AppConfig implements SchedulingConfigurer {
     @Override
     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
         taskRegistrar.setScheduler(taskScheduler());
         taskRegistrar.addTriggerTask(
             new Runnable() {
                 public void run() {
                     myTask().work();
                 }
             },
             new CustomTrigger()
         );
     }
     @Bean(destroyMethod="shutdown")
     public Executor taskScheduler() {
         return Executors.newScheduledThreadPool(42);
     }
     @Bean
     public MyTask myTask() {
         return new MyTask();
     }
 }

作为参考,可以将上面的示例与下面的Spring XML配置进行比较

<beans> 
    <task:annotation-driven scheduler="taskScheduler"/>
    <task:scheduler id="taskScheduler" pool-size="42"/>
    <task:scheduled-tasks scheduler="taskScheduler">
        <task:scheduled ref="myTask" method="work" fixed-rate="1000"/>
    </task:scheduled-tasks>
    <bean id="myTask" class="com.foo.MyTask"/>
</beans>

更多参考Scheduled、SchedulingConfiguration、SchedulingConfigurer、ScheduledTaskRegistrar、Trigger以及ScheduledAnnotationBeanPostProcessor。

【3】代码实例

Service如下(这里使用cron表达式):

@Service
public class ScheduledService {
  // 每天的整分调用一次该方法
    @Scheduled(cron = "0 * * * * 0-7")
    public void hello(){
        System.out.println("hello...");
    }
}

在主程序上添加@EnableScheduling注解如下:

@SpringBootApplication
@EnableScheduling
public class SpringBoot01CacheApplication {
  public static void main(String[] args) {
    SpringApplication.run(SpringBoot01CacheApplication.class, args);
  }
}


fixedRate ,fixedDelay 和initialDelay

代码示例如下:

  //上一次 项目启动时间点之后 5 秒执行一次
    @Scheduled(fixedRate = 5000)
    public void fixedRate(){
        System.out.println("fixedRate: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
    }
  //上一次 结束时间点之后 每50秒执行一次
    @Scheduled(fixedDelay = 50000)
    public void fixedDelay(){
        for (int i = 0; i < 10; i++){
            System.out.println("fixedDelay" + i  + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        }
    }
    // initialDelay :fixedRate() 或fixedDelay()第一次执行前延迟的毫秒数
  //第一次延迟50秒执行,之后按照fixedRate的规则每6秒执行一次
    @Scheduled(initialDelay = 50000,fixedRate = 6000)
    public void initialDelayFixedRate (){
        for (int i = 0; i < 10; i++){
            System.out.println("initialDelayFixedRate :" + i + new SimpleDateFormat("HH:mm:ss").format(new Date()) );
        }
    }

【4】cron表达式

cron表达式属性如下:

second(秒), minute(分), hour(时),day of month(日),month(月),day of week(周几)

字段与值表格如下:

image.png


特殊符号释义如下:

image.png

关于L的说明

L是"last"的缩写,只能在 “日”和“周”中使用。在“日”中设置,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年), 在“周”上表示周六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在“周”上设置”7L”这样的格式,则表示“本月最后一个周六”。

关于W的说明

表示离指定日期的最近那个工作日(周一至周五)触发,只能在 “日” 中使用且只能用在具体的数字之后。若在“日”上置 15W,表示离每月15号最近的那个工作日触发。假如15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发,如果15号正好在工作日(周一至周五),则就在该天触发。如果是 1W 就只能往本月的下一个最近的工作日推不能跨月往上一个月推。

关于#的说明

用于指定某个月份的第几个周几,只能作用于 “周” 上。例如,3#1 表示该月份的第一个星期二,而 5#2 表示该月份的第二个星期四。


示例如下:

0 0 5-22/2 * * ?  ---  每天5点到22点,每两小时执行一次
0 0 0 * * * -- 每天零时执行一次
0 0/15 14,18 * * ? -- 每天14点整和18点整,每隔15分钟执行一次
0 15 10 ? * 1-6 -- 每个月的周一到周六 10:15分执行一次
0 0 2 ? * 6L -- 每个月的最后一个周六凌晨2点执行一次
0 0 2 LW * ? -- 每个月的最后一个工作日凌晨2点执行一次
0 0 2-4 ? * 1#1 -- 每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次

实现定时任务的方式很多,其他的有JDK 自带的 TimerTask or Timer、使用开源作业调度框架 Quartz、线程池 ScheduleExecutorService 和其实现类ScheduledThreadPoolExecutor



目录
相关文章
|
8天前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
22 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
2月前
|
SQL Java 调度
实时计算 Flink版产品使用问题之使用Spring Boot启动Flink处理任务时,使用Spring Boot的@Scheduled注解进行定时任务调度,出现内存占用过高,该怎么办
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
3月前
|
Java 关系型数据库 MySQL
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
Mybatis入门之在基于Springboot的框架下拿到MySQL中数据
32 4
|
3月前
|
Java 应用服务中间件 Maven
Springboot入门基础知识详解 parent starter 引导类 辅助功能
Springboot入门基础知识详解 parent starter 引导类 辅助功能
33 2
|
3月前
|
Java 程序员
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
浅浅纪念花一个月完成Springboot+Mybatis+Springmvc+Vue2+elementUI的前后端交互入门项目
41 1
|
3月前
|
Java 调度 Spring
SpringBoot多个@Scheduled注解的方法,会阻塞吗
【6月更文挑战第9天】SpringBoot多个@Scheduled注解的方法,会阻塞吗
183 5
|
3月前
|
消息中间件 设计模式 Java
SpringBoot+Schedule 定时任务的配置开关
SpringBoot+Schedule 定时任务的配置开关
82 0
SpringBoot+Schedule 定时任务的配置开关
|
3月前
|
监控 Java 调度
Spring Boot中的定时任务调度
Spring Boot中的定时任务调度
|
4月前
|
安全 Java 数据库连接
在IntelliJ IDEA中通过Spring Boot集成达梦数据库:从入门到精通
在IntelliJ IDEA中通过Spring Boot集成达梦数据库:从入门到精通
799 6
|
4月前
|
SQL Java 调度
SpringBoot使用@Scheduled定时任务录入将要过期任务数据
SpringBoot使用@Scheduled定时任务录入将要过期任务数据
下一篇
DDNS