springboot集成schedule(深度理解)(代码片段)

_H_JY _H_JY     2022-12-06     134

关键词:

背景


 在项目开发过程中,我们经常需要执行具有周期性的任务。通过定时任务可以很好的帮助我们实现。

我们拿常用的几种定时任务框架做一个比较:

从以上表格可以看出,Spring Schedule框架功能完善,简单易用。对于中小型项目需求,Spring Schedule是完全可以胜任的。

 

 

1、springboot集成schedule


1.1 添加maven依赖包

由于Spring Schedule包含在spring-boot-starter基础模块中了,所有不需要增加额外的依赖。

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

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

 

1.2 启动类,添加启动注解

在springboot入口或者配置类中增加@EnableScheduling注解即可启用定时任务。

1

2

3

4

5

6

7

@EnableScheduling

@SpringBootApplication

public class ScheduleApplication

    public static void main(String[] args)

        SpringApplication.run(ScheduleApplication.class, args);

    

  

1.3.添加定时任务

我们将对Spring Schedule三种任务调度器分别举例说明。

1.3.1 Cron表达式

类似于Linux下的Cron表达式时间定义规则。Cron表达式由6或7个空格分隔的时间字段组成,如下图:

 

常用表达式:

 

举个栗子:

添加一个work()方法,每10秒执行一次。

注意:当方法的执行时间超过任务调度频率时,调度器会在下个周期执行。

如:假设work()方法在第0秒开始执行,方法执行了12秒,那么下一次执行work()方法的时间是第20秒。

1

2

3

4

5

6

7

@Component

public class MyTask

    @Scheduled(cron = "0/10 * * * * *")

    public void work()

        // task execution logic

    

 

1.3.2 固定间隔任务

 下一次的任务执行时间,是从方法最后一次任务执行结束时间开始计算。并以此规则开始周期性的执行任务。

举个栗子:

添加一个work()方法,每隔10秒执行一次。

例如:假设work()方法在第0秒开始执行,方法执行了12秒,那么下一次执行work()方法的时间是第22秒。

1

2

3

4

@Scheduled(fixedDelay = 1000*10)

public void work()

    // task execution logic

  

1.3.3 固定频率任务

 按照指定频率执行任务,并以此规则开始周期性的执行调度。

举个栗子:

添加一个work()方法,每10秒执行一次。

注意:当方法的执行时间超过任务调度频率时,调度器会在当前方法执行完成后立即执行下次任务。

例如:假设work()方法在第0秒开始执行,方法执行了12秒,那么下一次执行work()方法的时间是第12秒。

1

2

3

4

@Scheduled(fixedRate = 1000*10)

public void work()

    // task execution logic

 

 

2、配置TaskScheduler线程池


 在实际项目中,我们一个系统可能会定义多个定时任务。那么多个定时任务之间是可以相互独立且可以并行执行的。

通过查看org.springframework.scheduling.config.ScheduledTaskRegistrar源代码,发现spring默认会创建一个单线程池。这样对于我们的多任务调度可能会是致命的,当多个任务并发(或需要在同一时间)执行时,任务调度器就会出现时间漂移,任务执行时间将不确定。

1

2

3

4

5

6

7

protected void scheduleTasks()

    if (this.taskScheduler == null)

        this.localExecutor = Executors.newSingleThreadScheduledExecutor();

        this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);

    

    //省略...

  

2.1 自定义线程池

新增一个配置类,实现SchedulingConfigurer接口。重写configureTasks方法,通过taskRegistrar设置自定义线程池。

1

2

3

4

5

6

7

8

9

10

11

12

@Configuration

public class ScheduleConfig implements SchedulingConfigurer

    @Override

    public void configureTasks(ScheduledTaskRegistrar taskRegistrar)

        taskRegistrar.setScheduler(taskExecutor());

    

     

    @Bean(destroyMethod="shutdown")

    public Executor taskExecutor()

        return Executors.newScheduledThreadPool(20);

    

 

 

3、实际应用中的问题


 3.1 Web应用中的启动和关闭问题

我们知道通过spring加载或初始化的Bean,在服务停止的时候,spring会自动卸载(销毁)。但是由于线程是JVM级别的,如果用户在Web应用中启动了一个线程,那么这个线程的生命周期并不会和Web应用保持一致。也就是说,即使Web应用停止了,这个线程依然没有结束(死亡)。

解决方法:

1)当前对象是通过spring初始化

spring在卸载(销毁)实例时,会调用实例的destroy方法。通过实现DisposableBean接口覆盖destroy方法实现。在destroy方法中主动关闭线程。

1

2

3

4

5

6

7

8

9

10

@Component

public class MyTask implements DisposableBean

    @Override

    public void destroy() throws Exception

        //关闭线程或线程池

        ThreadPoolTaskScheduler scheduler = (ThreadPoolTaskScheduler)applicationContext.getBean("scheduler");

        scheduler.shutdown();

    

    //省略...

 

2)当前对象不是通过spring初始化(管理)

那么我们可以增加一个Servlet上下文监听器,在Servlet服务停止的时候主动关闭线程。

1

2

3

4

5

6

7

public class MyTaskListenter implements ServletContextListener

    @Override

    public void contextDestroyed(ServletContextEvent arg0)

        //关闭线程或线程池

    

    //省略...

 

 

3.2 分布式部署问题

在实际项目中,我们的系统通常会做集群、分布式或灾备部署。那么定时任务就可能出现并发问题,即同一个任务在多个服务器上同时在运行。

解决方法(分布式锁):

1)通过数据库表锁

2)通过缓存中间件

3)通过Zookeeper实现

 

总结:

spring schedule给我们提供了一套简单、快速、高效、稳定的定时任务框架。但需要考虑线程的生命周期及分布式部署问题。

 

玩转springboot集成篇(@scheduled静态动态定时任务)(代码片段)

publicstaticvoidmain(String[]args)SpringApplication.run(DemoApplication.class,args);privatestaticfinalLoglogger=LogFactory.getLog(DownLoadTask.class);@Scheduled(cron="00/5***?")publicvoidjustDoIt()log 查看详情

springboot整合@scheduled定时计划

 SpringBoot集成了@Scheduled的相关依赖(org.springframework.scheduling.annotation.Scheduled);我们只需要直接使用即可。@Scheduled注解的使用步骤:第一步:在启动类上面启用定时任务 第二步:在要定时执行的方法上面,加上@Scheduled注解,并指... 查看详情

springboot集成quartz动态定时任务

SpringBoot自带schedule沿用的springboot少xml配置的优良传统,本身支持表达式等多种定时任务注意在程序启动的时候加上@EnableScheduling@Scheduled(cron="0/5****?")publicvoidjob()System.out.println("每五秒执行一次");为什么要... 查看详情

java程序员学深度学习djl上手2springboot集成(代码片段)

Java程序员学深度学习DJL上手2Springboot集成一、准备环境二、新建项目三、pom.xml四、源代码1.SpringBoot入口2.Controller3.application.xml五、使用方式1.运行程序:2.打开网页3.上传要识别的图片4.下载识别结果一、准备环境windowsideajdk11m... 查看详情

springboot集成quartz动态定时任务

SpringBoot自带schedule沿用的springboot少xml配置的优良传统,本身支持表达式等多种定时任务注意在程序启动的时候加上@EnableScheduling@Scheduled(cron="0/5****?")publicvoidjob()System.out.println("每五秒执行一次");为什么要... 查看详情

springboot入门:集成quartz定时任务

本片文章续《SpringBoot入门(八):集成RabbitMQ消息队列》,关于Quartz定时任务请参考《Quartz的基本使用之入门(2.3.0版本)》springboot实现定时任务,除了集成Quartz外,还可以直接使用scheduler注解。使用1个简单的注解就可以完成... 查看详情

springboot下schdule的配置与使用

...定时任务,这个时候使用定时任务就能很方便的实现。在SpringBoot中用得最多的就是Schedule。一、SpringBoot集成Schedule1、依赖配置由于Schedule就包含在spring-boot-starter中,所以无需引入其他依赖。2、启用定时任务在启动类或者配置类... 查看详情

springboot2.1.1.release集成quartz

SpringBoot2.1.1.RELEASE集成quartzhttp://www.qchcloud.cn/system/article/show/70依赖配置:<!--定时任务--><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</arti 查看详情

springboot集成quartz动态定时任务

SpringBoot集成Quartz动态定时任务项目中需要用到定时任务,考虑了下java方面定时任务无非就三种:用Java自带的timer类。稍微看了一下,可以实现大部分的指定频率的任务的调度(timer.schedule()),也可以实现关闭和开启(timer.ca... 查看详情

springboot集成quartz实现任务调度

...模式组件模式链式写法体系结构调度器任务触发器架构图springbootquartzpom配置<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</a 查看详情

springboot源码解析-----springboot精髓:集成aop

本篇主要集成Sping一个重要功能AOP我们还是先回顾一下以前Spring中是如何使用AOP的,大家可以看看我这篇文章spring5源码深度解析-----AOP的使用及AOP自定义标签Spring中使用AOP引入Aspect<dependency><groupId>org.aspectj</groupId><... 查看详情

springboot项目怎么调用深度算法

您好,springboot项目调用深度算法的具体方法如下:SpringBoot是一个快速开发的Java框架,它可以让开发者快速构建Web应用程序。深度学习算法是一种机器学习算法,它可以处理大量的数据并从中学习。要在SpringBoot项目中调用深度学... 查看详情

springboot@scheduled并发

本文介绍如何使用springboot的sheduled实现任务的定时调度,并将调度的任务实现为并发的方式。 1、定时调度配置scheduled1)注册定时任务packagecom.xiaoju.dqa.sentinel.scheduler;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframew 查看详情

springboot学习18:springboot使用scheduled定时任务器

Scheduled定时任务器:是Spring3.0以后自带的一个定时任务器。1、在pom.xml文件中添加Scheduled依赖<!--添加spring定时任务Scheduled坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-context 查看详情

springboot@scheduled未生效原因

参考技术A在springboot中,支持多种定时执行模式(cron,fixRate,fixDelay),在Application或者其他Autoconfig上增加@EnableScheduling注解开启。然后在指定方法增加@Scheduled注解,如下:需要注意的是,如果在多个函数上使用了@Scheduled,那么一... 查看详情

springboot动态的配置scheduling

参考技术A一:springboot配置静态定时任务1:pom中添加依赖2:启动类中加入@EnableScheduling来开启定时任务3:@Scheduled(cron= "0/10****?")//每过10秒执行一次二: springboot动态配置定时任务:主要动态的配置。packagecom.example.... 查看详情

springboot定时任务@scheduled注解

...到使用定时器循环订单时间,然后将超时的订单状态更改.springboot的@Scheduled注解能够很快速完成我们需要的定时任务.@ComponentpublicclassExampleTimer{SimpleDateFormatdateFormat=newSimpleDateFormat("HH:mm:ss");/*每100秒执行一次*/@Schedu 查看详情

springboot@scheduled未生效原因以及相关坑

在springboot中,支持多种定时执行模式(cron,fixRate,fixDelay),在Application或者其他Autoconfig上增加@EnableScheduling注解开启。然后在指定方法增加@Scheduled注解,如下:@Scheduled(cron="000/1**?")publicvoidupdateTime(){current_log_time_appendix=s 查看详情