第二十一章 : Spring Boot 集成定时任务(一)

第二十一章 : Spring Boot 集成定时任务(一)

前言

本章知识点: 介绍使用Spring Boot内置的@Scheduled注解来实现定时任务-单线程和多线程;以及介绍Quartz定时任务调度框架:简单定时调度器(SimpleSchedule)和Cron表达式调度器(CronSchedule)来调度触发的定时任务。

Springboot 版本 2.3.2.RELEASE ,RabbitMQ 3.9.11,Erlang 24.2

场景

  1. 系统维护:操作系统和各种软件通常需要定期进行更新和打补丁。通过定时任务,这些更新可以在预定时间自动进行,无需人工干预。
  2. 文件同步:在多个设备或服务器之间同步文件时,可以使用定时任务来确保文件的一致性。例如,使用cron在Linux系统上定期同步文件夹。
  3. 发送通知或警报:许多系统需要定期发送通知或警报,如系统状态报告,警报阈值越过通知等。这些可以通过定时任务来实现。
  4. 数据抽取和加载:在大数据环境中,通常需要从不同的数据源抽取数据,并将其加载到数据仓库或分析系统中。定时任务可以定期执行这些操作。
  5. 测试和监控:定期进行系统或应用的健康检查,性能测试等,以便及时发现问题并进行修复。
  6. 日志清理:定期清理过期的日志文件,以防止磁盘空间被耗尽。
  7. 网关定期同步:对于需要和远程系统进行同步的网关服务,定时任务可以帮助实现数据的定期更新。
  8. 定期重新启动服务:某些服务可能需要定期重新启动以保持良好的性能。定时任务可以执行这个操作。
  9. 定期更新统计信息:在各种系统中,统计信息的及时更新对于决策制定和性能优化都非常重要。定时任务可以帮助实现这个需求。

Spring Boot定时任务的方式

Spring Boot提供了两种实现定时任务的方式:

1) 一种是Spring Boot内置的注解方式,只需在类上增加@Scheduled即可实现;

2)另一种是基于Quartz实现,Quartz是目前完善的定时任务解决方案,适合处理复杂的应用场景。

@Scheduled定时任务
参数说明
  1. value:指定计划任务的时间间隔。可以是固定时间间隔的字符串表示,例如"0 0/5 * * * ?"表示每5分钟执行一次。也可以是cron表达式,例如"0 0 12 * * ?"表示每天中午12点执行。
  2. fixedRate:固定速率,表示任务以固定的时间间隔执行。如果设置了该参数,那么方法会在每隔一定时间间隔后执行一次。与value参数类似,参数值可以是固定的时间间隔字符串或cron表达式。
  3. fixedDelay:固定延迟,表示任务在完成一次执行后,等待一定的延迟时间再执行下一次。与value参数类似,参数值可以是固定的时间间隔字符串或cron表达式。
  4. initialDelay:初始延迟,表示任务在启动后需要等待一定的延迟时间才开始执行。参数值可以是固定的时间间隔字符串或cron表达式。
  5. cron:cron表达式,用于指定任务的执行时间。可以精确到秒级别。例如,"0 0 12 * * ?"表示每天中午12点执行。
  6. timezone:时区,用于指定任务的执行时间。该参数通常与cron表达式一起使用,以确定任务在特定时区中的执行时间。
  7. threadName:线程名称,用于指定执行任务的线程名称。如果未设置该参数,则默认使用"ScheduledThreadExecutor"。
  8. inheritable:是否可继承,表示是否允许子类继承该注解的设置。默认为false。
  9. stateful:是否状态保持,表示是否在每次执行任务时都保持状态。默认为false。
  10. jobName:任务名称,用于指定计划任务的名称。如果未设置该参数,则默认使用方法名称作为任务名称。
  11. jobGroup:任务组,用于将相关的计划任务分组在一起执行。如果未设置该参数,则默认使用方法所属的类作为任务组。
代码示例

Spring Boot提供了内置的@Scheduled注解实现定时任务的功能。使用@Scheduled注解创建定时任务非常简单,只需几行代码即可完成。

注意:默认情况下,Spring Boot定时任务是单线程方式执行的。

如果同一时刻有两个定时任务需要执行,那么只能在一个定时任务完成之后再执行下一个。

如果只有一个定时任务,这样做肯定没问题;当定时任务增多时,如果一个任务被阻塞,则会导致其他任务无法正常执行。要解决这个问题,需要配置任务调度线程池。

单线程定时任务
  1. 创建定时任务类

    首先创建SchedulerTask类,然后在任务方法上添加@Scheduled注解,@EnableScheduling开启定时任务,具体的代码如下:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
    import java.util.Date;
    @EnableScheduling
    @Component
    @Slf4j
    public class SchedulerTask {@Scheduled(cron="*/10 * * * * ?")protected void taskCron(){SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");log.info("现在时间Scheduled1: {}" , dateFormat.format(new Date()));}
    }
    
  2. 启动项目

    创建好SchedulerTask定时任务后启动项目,查看后台任务的运行情况,如图22-1所示。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication(scanBasePackages = "org.sea.example.day14.task")
    public class SpringbootDay14Application {public static void main(String[] args) {SpringApplication.run(SpringbootDay14Application.class, args);}}
    

    在这里插入图片描述

    ​ 图22-1 后台定时任务执行日志

    后台日志显示,SchedulerTask任务每隔10秒输出当前时间,说明定义的任务正在后台定时执行

多线程定时任务
  1. 增加多线程配置类

    增加SchedulerConfig配置类,代码如下:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;
    @Configuration
    @Slf4j
    public class SchedulerConfig {@Beanpublic Executor asyncTaskScheduler() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(3);executor.setMaxPoolSize(10);executor.setQueueCapacity(3);executor.initialize();log.info("多线程配置类初始化");return executor;}
    }
    

    设置执行线程池为3,最大线程数为10。

  2. SchedulerTask定时任务

    在类上增加@EnableAsync注解,在方法上增加@Async注解,使得后台任务能够异步执行,代码如下:

    mport lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
    import java.util.Date;@EnableAsync
    @EnableScheduling
    @Component
    @Slf4j
    public class SchedulerAsyncTask {@Async@Scheduled(cron="*/10 * * * * ?")protected void task1(){SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");log.info("现在时间Scheduled1: {}" , dateFormat.format(new Date()));}@Async@Scheduled(cron="*/10 * * * * ?")protected void task2(){SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");log.info("现在时间Scheduled2: {}" , dateFormat.format(new Date()));}@Async@Scheduled(cron="*/10 * * * * ?")protected void task3(){SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");log.info("现在时间Scheduled3: {}" , dateFormat.format(new Date()));}
    }
    

    ​ 在上面的示例中,定时任务类SechedulerTask增加了@EnableAsync注解,开启了异步事件支持。同时,在定时方法上增加@Async注解,使任务能够异步执行,这样各个后台任务就不会阻塞。

    1. 启动项目

      创建好SchedulerTask定时任务后启动项目,查看后台任务的运行情况,如图22-2所示。

      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication(scanBasePackages = "org.sea.example.day14.task2")
      public class SpringbootDay14Application {public static void main(String[] args) {SpringApplication.run(SpringbootDay14Application.class, args);}}

      在这里插入图片描述

      ​ 图22-2 后台定时任务执行日志

      通过后台日志可以看到,Spring Boot启动线程池负责调度执行后台任务,各个后台任务之间相对独立、互不影响。

Quartz

1、什么是Quartz?

Quartz是OpenSymphony开源组织在任务调度(Job Scheduling,也称为作业调度)领域下的开源项目,它是Java开发的开源任务调度管理系统,具有使用灵活、配置简单的特点,能够实现复杂应用场景下的任务调度管理。当定时任务愈加复杂时,使用Spring Boot注解@Scheduled已经不能满足业务需要。相比之下,Quartz灵活而又不失简单,能够创建简单或复杂的调度任务,其主要具有如下功能:

1)持久化:将任务和状态持久化到数据库。

2)任务管理:对调度任务进行有效的管理。

3)集群:借助关系数据库和JDBC任务存储支持集群。

2、 Quartz的基本概念

Quartz是一个由Java开发的开源框架,用于执行定时任务。以下是Quartz的一些基本概念:

  1. Job:Job是一个接口,代表一个具体的任务。任务的具体逻辑在execute方法中实现。每次执行Job时,Quartz都会重新创建一个Job实例。
  2. JobDetail:用于定义Job的实例。因为相同的任务逻辑可能会被多次执行,所以使用JobDetail来创建每个独立的Job实例,确保各个任务可以独立运行。
  3. Trigger:Trigger是一个接口,用于定义执行给定Job的时间规则。主要有SimpleTrigger和CronTrigger这两个子接口。
  4. Scheduler:Scheduler是一个接口,代表Quartz的独立运行容器,用于与调度程序交互。
  5. JobBuilder:用于定义或构建JobDetail实例,帮助创建Job的实例。
  6. TriggerBuilder:用于定义或构建Trigger实例。

Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组和名称,组和名称是Scheduler查找、定位容器中某个对象的依据,Trigger的组和名称必须唯一,JobDetail的组和名称也必须唯一(但可以与Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组和名称访问控制容器中的Trigger与JobDetail。

总而言之,Scheduler相当于一个容器,其中包含各种Job和Trigger,四者之间的关系如图22-3所示

在这里插入图片描述

​ 图22-3 四者之间的关系图

Quartz通过Scheduler触发Trigger规则实现任务的管理和调度。除此之外,Quartz还提供了TriggerBuilderJobBuilder类来构建Trigger实例和Job实例。

Quartz主要有简单定时调度器(SimpleSchedule)和Cron表达式调度器(CronSchedule)来调度触发的定时任务。下面通过示例演示这两种调度器的用法。

简单定时调度器(SimpleSchedule
  1. 添加Quartz依赖

    在pom.xml中配置Quartz的依赖包spring-boot-starter-quartz,具体配置如下:

    		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency>
    
  2. 创建任务

    创建定时任务的实现类SimpleJob,并继承QuartzJobBean,示例代码如下:

    import lombok.extern.slf4j.Slf4j;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.springframework.scheduling.quartz.QuartzJobBean;@Slf4j
    public class SimpleJob extends QuartzJobBean {private String name;public void setName(String name) {this.name = name;}@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info(String.format("Hello %s!", this.name));}
    }
    
  3. 构建JobDetail、CronTrigger

    接下来构建JobDetail和Trigger实例。首先使用SimpleScheduleBuilder创建Scheduler实例,然后关联JobDetail和Trigger实例。示例代码如下:

    import org.quartz.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;@Configuration
    public class SimpleScheduler {@Beanpublic JobDetail simpleJobDetail() {return JobBuilder.newJob(SimpleJob.class).withIdentity("simpleJobDetail").usingJobData("name", "test simpleJob").storeDurably().build();}@Beanpublic Trigger sampleJobTrigger() {SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever();return TriggerBuilder.newTrigger().forJob(simpleJobDetail()).withIdentity("sampleJobTrigger").withSchedule(scheduleBuilder).build();}
    }
    
  4. 运行任务

    启动项目,验证任务是否能正常运行。如图22-4所示,

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    /**修改scanBasePackages */
    @SpringBootApplication(scanBasePackages = "org.sea.example.day14.job")
    public class SpringbootDay14Application {public static void main(String[] args) {SpringApplication.run(SpringbootDay14Application.class, args);}}
    

    在这里插入图片描述

    ​ 图22-4 简单任务运行日志

    SimpleJob后台任务成功运行,每隔10秒执行一次,这说明使用SimpleSchedule创建简单的定时任务运行成功。

Cron表达式调度器(CronSchedule
  1. 定义Job

    import lombok.extern.slf4j.Slf4j;
    import org.quartz.JobExecutionContext;
    import org.quartz.JobExecutionException;
    import org.springframework.scheduling.quartz.QuartzJobBean;@Slf4j
    public class CronJob extends QuartzJobBean {private String name;public void setName(String name) {this.name = name;}@Overrideprotected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info(String.format("Hello %s!", this.name));}
    }
    
  2. 构建JobDetail、CronTrigger

    import org.quartz.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;@Configuration
    public class CronScheduler {@Beanpublic JobDetail cronJobDetail() {return JobBuilder.newJob(CronJob.class).withIdentity("cronJobDetail").usingJobData("name", "test cronJob").storeDurably().build();}@Beanpublic Trigger cronJobTrigger() {CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");return TriggerBuilder.newTrigger().forJob(cronJobDetail()).withIdentity("cronJobTrigger").withSchedule(scheduleBuilder).build();}
    }
    
  3. 运行任务

    启动项目,验证任务是否能正常运行。如图22-5所示,

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    /**修改scanBasePackages */
    @SpringBootApplication(scanBasePackages = "org.sea.example.day14.job2")
    public class SpringbootDay14Application {public static void main(String[] args) {SpringApplication.run(SpringbootDay14Application.class, args);}}
    

    在这里插入图片描述

    ​ 图22-5 Cron定时任务运行日志

    CronJob后台任务成功运行,每隔10秒执行一次,这说明使用CronScheduleBuilder创建简单的定时任务运行成功。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/233713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Dubbo线程池

前言 Dubbo使用Netty作为网络调用框架&#xff0c;Netty是一个Reactor模型的框架&#xff0c;线程模型分为boss线程池和worker线程池&#xff0c;boss线程池负责监听、分配事件&#xff0c;worker线程池负责处理事件&#xff0c;简单说就是boss线程池负责hold请求&#xff0c;并…

C++的static用法总结和代码示例

static用法 修饰普通变量&#xff1a;static关键字可用于修改普通变量的存储区域和生命周期&#xff0c;使其存储在静态区&#xff0c;在程序运行前就分配了空间。如果有初始值&#xff0c;将使用初始值进行初始化&#xff0c;否则系统会用默认值初始化它。修饰普通函数&#…

【算法】选择排序

1、排序逻辑 选择排序逻辑&#xff1a;对数组中的数据&#xff0c;先假定一个最小的数据下标&#xff0c;然后进行循环寻找到最小数据的下标&#xff0c;放在第一层循环的最初始位置 例&#xff1a; 从0 ~ N-1 寻找到最小值&#xff0c;放在0位置 从1~N-1 寻找到最小值 &…

自定义IDEA代码补全插件

目标&#xff1a; 对于项目中的静态方法&#xff08;主要是各种工具类里的静态方法&#xff09;&#xff0c;可以在输入方法名时直接提示相关的静态方法&#xff0c;选中后自动补全代码&#xff0c;并导入静态类。 设计&#xff1a; 初步构想&#xff0c;用户选择要导入的文…

SearchWP WordPress高级网站内容搜索插件

点击阅读SearchWP WordPress高级网站内容搜索插件原文 SearchWP WordPress高级网站内容搜索插件是一个非常强大的工具&#xff0c;可以显着增强您网站的搜索功能。通过向网站访问者提供高度相关和精确的搜索结果&#xff0c;它可以有效地简化他们的搜索过程&#xff0c;促进发…

CentOS 8离线安装telnet

下载telnet rpm安装包&#xff0c;可从https://www.rpmfind.net/linux/rpm2html/search.php?querytelnet&submitSearch…&systemcentos&arch 根据自己的操作系统下载对应的包&#xff0c;这里以CentOS8为例,分别下载如下的rtp包 xinetd-2.3.15-24.el8.x86_64.rpm…

设计师必备的Figma可视化组件库资产已更新至 7.0版本

在当今数字化时代&#xff0c;数据量呈爆炸式增长&#xff0c;大屏可视化的主要程度越来越高&#xff0c;而大屏背后的设计师们面对的挑战也越来越多&#xff0c;其中之一就是大屏可视化设计项目中的重复性元素设计。这一过程不仅耗费时间&#xff0c;还明显降低了设计团队的生…

Qt6.5类库详解:QLineEdit

哈喽大家好&#xff0c;我是20YC小二&#xff01;欢迎关注(20YC编程)&#xff0c;现在有免费《C程序员》视频教程下载哦&#xff01; ~下面开始今天的分享内容~ 1. QLineEdit介绍 QLineEdit是一个单行文本编辑器&#xff0c;允许用户输入和编辑纯文本。它提供了许多有用的编辑…

周记 从现在开始

每周笔记 2023&#xff1a;12.11 早上&#xff1a; ​ 全是课 下午&#xff1a; ​ 全是课 晚上&#xff1a; ​ 全是课 什么也没学 2023&#xff1a;12.12 早上&#xff1a; ​ 全是课 下午&#xff1a; ​ 全是课 晚上&#xff1a; ​ 全是课 什么也没学 20…

SSH的交互原理(wireshark的分析)

SSH的交换原理&#xff08;wireshark篇&#xff09; 首先要想了解ssh的交换原理&#xff0c;必须要先了解他的加密方式&#xff0c;他的加密方式是对称加密&#xff0c;和公钥加密。什么意思呢&#xff1f; 首先我们向服务器发送一个请求&#xff0c;然后服务器会发给我们他的…

GitBook安装及使用——使用 Markdown 创建你自己的博客网站和电子书

目录 前言一、依赖环境二、gitbook安装使用1.安装 gitbook-cli2.安装 gitbook3.Gitbook初始化4.创建你的文章5.修改 SUMMARY.md 和 README.md6.编译生成静态网页7.运行以便在浏览器预览8.运行效果 前言 GitBook是一个命令行工具&#xff0c;用于使用 Markdown 构建漂亮的博客网…

SSE(服务器推送事件)规范

SSE 是指 "Server-Sent Events"&#xff0c;即服务器推送事件。它是一种基于 HTTP 的服务器推送技术&#xff0c;允许服务器实时向客户端推送数据。SSE 规范定义了一种在客户端和服务器之间单向实时通信的方式&#xff0c;通常用于实现服务器向客户端推送更新、通知或…

【matlab】MATLAB常用内置函数示例

目录: 数值计算函数 1.1 abs函数 1.2 sin、cos、tan函数 1.3 exp、log函数 1.4 sqrt函数 1.5 sum、prod函数 矩阵和向量操作函数 2.1 size函数 2.2 reshape函数 2.3 repmat函数 2.4 eye函数 2.5 rand、randn函数 绘图函数 3.1 plot函数 3.2 scatter函数 3.3 bar函数 3.4 hist函…

面试题总结(十四)【系统移植】【华清远见西安中心】

你用过哪些Bootloader&#xff1f;有什么区别&#xff1f; 作为一个AI助手&#xff0c;我没有直接使用过Bootloader。但我可以为您提供一些关于常见Bootloader的信息和他们之间的区别。 1. GRUB (GRand Unified Bootloader)&#xff1a;GRUB是一个功能强大且广泛使用的Bootload…

【鉴权】JWT加密

目录 定义 官网 定义 JWT是JSON Web Token的缩写&#xff0c;是RFC7519规范。该规范目的是为了让客户端和服务端可靠的传递信息。 官网 JSON Web Tokens - jwt.io JWT是由三个部分组成&#xff0c;HMACSHA256( base64UrlEncode(header) "." base64UrlEncode(pa…

rk3568 MDIO总线

rk3568 MDIO总线 MDIO(Management Data Input/Output)是一种管理数据输入/输出协议,用于在以太网交换机和PHY(物理层收发器)之间进行通信。在网络设备中,MDIO总线用于控制网络接口的PHY芯片,例如通过MDIO总线访问PHY芯片的寄存器。这些寄存器包含了一些关于网络连接状态…

AWS 知识二:AWS同一个VPC下的ubuntu实例通过ldapsearch命令查询目录用户信息

前言&#xff1a; 前提&#xff1a;需要完成我的AWS 知识一创建一个成功运行的目录。 主要两个重要&#xff1a;1.本地windows如何通过SSH的方式连接到Ubuntu实例 2.ldapsearch命令的构成 一 &#xff0c;启动一个新的Ubuntu实例 1.创建一个ubuntu实例 具体创建实例步骤我就不…

vue el-date-picker中datetime类型对今天之后的日期包含时分禁用

vue el-date-picker中datetime类型对今天之后的日期包含时分禁用 目前对选择秒那一列未禁用 <template><div><el-date-pickerv-model"deactivateTime"type"datetime"format"yyyy-MM-dd HH:mm:ss"value-format"yyyy-MM-dd HH…

抖音直播间websocket礼物和弹幕消息推送可能出现重复的情况,解决办法

在抖音直播间里&#xff0c;通过websocket收到的礼物消息数据格式如下&#xff1a; {common: {method: WebcastGiftMessage,msgId: 7283420150152942632,roomId: 7283413007005207308,createTime: 1695803662805,isShowMsg: True,describe: 莎***:送给主播 1个入团卡,priority…

HarmonyOS4.0从零开始的开发教程17给您的应用添加通知

HarmonyOS&#xff08;十五&#xff09;给您的应用添加通知 通知介绍 通知旨在让用户以合适的方式及时获得有用的新消息&#xff0c;帮助用户高效地处理任务。应用可以通过通知接口发送通知消息&#xff0c;用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应…