Springboot定时任务

@Component
@EnableScheduling
public class SpringBootTestJob {@Scheduled(cron = "0/5 * * * * ?")public void testScheduled(){System.out.println("SpringBootTestJob test");}
}

这段代码使用了 Spring Boot 自带的定时任务机制。解释如下:

  • @Component:这是一个 Spring 的注解,表示将该类标识为 Spring 容器中的一个 Bean,让 Spring 自动管理它的生命周期。

  • @EnableScheduling:启用 Spring 的调度任务功能。它会在 Spring 容器中创建一个 TaskScheduler,使得 @Scheduled 注解的任务能够按照指定的时间调度运行。

  • @Scheduled(cron = “0/5 * * * * ?”):这是定时任务的核心注解。cron 表达式定义了任务执行的时间规则:

    • 0/5 * * * * ? 表示每隔 5 秒执行一次任务。
      • 0/5:从第 0 秒开始,每 5 秒执行一次;
      • *:每分钟都执行;
      • *:每小时都执行;
      • *:每天都执行;
      • *:每月都执行;
      • ?:不指定星期几(因为月份和星期几的参数冲突时使用 ?)。

这段代码每隔 5 秒打印一次 "SpringBootTestJob test"

适用场景:
  • Spring Boot 内置的定时任务功能适合一些简单的定时任务,尤其是单个节点环境下。
  • 它适合不需要复杂调度、持久化、分布式支持等的场景。

2. 为什么有时候不用 Spring Boot 自带的定时任务?

虽然 Spring Boot 自带的定时任务使用方便,但有一些局限性,尤其是在更复杂的生产环境中,可能无法满足一些需求:

1. 只适合单体,不适合集群:
  • Spring Boot 自带的定时任务在单节点上很好用,但是在集群环境中,所有节点都可能执行相同的定时任务,从而导致任务重复执行,造成问题。
  • 解决方法:可以通过加分布式锁等方式来避免重复执行,但这种方式实现起来相对复杂,且不够灵活。
2. 无法实时更改定时任务状态和策略:
  • 如果你需要动态地停止、修改、重新调度任务,Spring Boot 自带的定时任务就显得不够灵活了。
  • 比如,如果在生产环境中需要临时停止某个定时任务,Spring Boot 的 @Scheduled 注解方式并不容易实现动态控制。
3. 无法持久化任务信息:
  • Spring Boot 自带的定时任务没有持久化机制,如果应用重启,所有定时任务会丢失。虽然可以利用数据库或其他持久化方式实现,但它本身不提供这些功能。

3. Quartz 框架的介绍

Quartz 是一个功能强大的作业调度框架,可以解决上述 Spring Boot 自带定时任务的不足,尤其在集群、持久化、灵活性等方面表现优异。

引入 Quartz 依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

Spring Boot 提供了对 Quartz 的支持,只需要引入这个依赖,框架会自动配置一些 Quartz 的基础设置。

配置 Quartz 定时任务:
@Configuration
public class QuartzConfig {/*** 声明一个任务* @return*/@Beanpublic JobDetail jobDetail() {return JobBuilder.newJob(TestJob.class).withIdentity("TestJob", "test").storeDurably()  // 表示即使没有触发器,任务也会被持久化.build();}/*** 声明一个触发器,什么时候触发这个任务* @return*/@Beanpublic Trigger trigger() {return TriggerBuilder.newTrigger().forJob(jobDetail()).withIdentity("trigger", "trigger").startNow()  // 立即开始.withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?"))  // 每两秒执行一次.build();}
}
  • JobDetail:表示要执行的作业,即 Quartz 任务类。使用 JobBuilder 创建一个作业实例并指定标识符。
  • Trigger:表示触发器,控制何时执行这个作业。CronScheduleBuilder 用来根据 Cron 表达式设定定时规则。
Quartz Job 类:
#禁用并发执行
@DisallowConcurrentExecution
public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("TestJob TEST开始");// 模拟任务执行System.out.println("TestJob TEST结束");}
}
  • @DisallowConcurrentExecution:表示任务不允许并发执行,即在任务没有完成之前,不会再次执行这个任务。
  • JobExecutionContext:上下文信息,包含了任务的所有执行信息。
让quartz将定时调度的任务保存到数据库中

1. 创建数据库表

首先,在数据库中创建相关的 Quartz 表来存储调度任务的状态、触发器和其他相关信息。以下是创建表的 SQL 语句:

-- Quartz 默认的数据库表
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;-- 创建 QRTZ_JOB_DETAILS 表
CREATE TABLE QRTZ_JOB_DETAILS (SCHED_NAME VARCHAR(120) NOT NULL COMMENT '定时任务名称',JOB_NAME VARCHAR(200) NOT NULL COMMENT 'job名称',JOB_GROUP VARCHAR(200) NOT NULL COMMENT 'job组',DESCRIPTION VARCHAR(250) NULL COMMENT '描述',JOB_CLASS_NAME VARCHAR(250) NOT NULL COMMENT 'job类名',IS_DURABLE VARCHAR(1) NOT NULL COMMENT '是否持久化',IS_NONCONCURRENT VARCHAR(1) NOT NULL COMMENT '是否非同步',IS_UPDATE_DATA VARCHAR(1) NOT NULL COMMENT '是否更新数据',REQUESTS_RECOVERY VARCHAR(1) NOT NULL COMMENT '请求是否覆盖',JOB_DATA BLOB NULL COMMENT 'job数据',PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
);-- 创建 QRTZ_TRIGGERS 表
CREATE TABLE QRTZ_TRIGGERS (SCHED_NAME VARCHAR(120) NOT NULL COMMENT '定时任务名称',TRIGGER_NAME VARCHAR(200) NOT NULL COMMENT '触发器名称',TRIGGER_GROUP VARCHAR(200) NOT NULL COMMENT '触发器组',JOB_NAME VARCHAR(200) NOT NULL COMMENT 'job名称',JOB_GROUP VARCHAR(200) NOT NULL COMMENT 'job组',DESCRIPTION VARCHAR(250) NULL COMMENT '描述',NEXT_FIRE_TIME BIGINT(13) NULL COMMENT '下一次触发时间',PREV_FIRE_TIME BIGINT(13) NULL COMMENT '前一次触发时间',PRIORITY INTEGER NULL COMMENT '等级',TRIGGER_STATE VARCHAR(16) NOT NULL COMMENT '触发状态',TRIGGER_TYPE VARCHAR(8) NOT NULL COMMENT '触发类型',START_TIME BIGINT(13) NOT NULL COMMENT '开始时间',END_TIME BIGINT(13) NULL COMMENT '结束时间',CALENDAR_NAME VARCHAR(200) NULL COMMENT '日程名称',MISFIRE_INSTR SMALLINT(2) NULL COMMENT '未触发实例',JOB_DATA BLOB NULL COMMENT 'job数据',PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME, JOB_NAME, JOB_GROUP)
);-- 其他表的创建省略...

这些表会用来存储定时任务的详细信息、触发器信息等。

2. 配置 Scheduler 使用数据库存储

为了让 Quartz 使用数据库来保存任务调度信息,我们需要在 application.propertiesapplication.yml 文件中进行相应配置。如下所示:

# Quartz 配置,使用 JDBCJobStore 存储任务
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource = quartzDataSource
org.quartz.jobStore.tablePrefix = QRTZ_# 数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/quartz_db?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-active=20

这些配置使得 Quartz 使用 MySQL 数据库并将调度信息保存到数据库中。

3. 配置 JobFactoryScheduler

在 Spring Boot 项目中,Quartz 使用 SchedulerFactoryBean 来创建和配置调度器。你可以通过自定义 JobFactory 来注入 Spring 管理的 Bean。以下是增强后的 MyJobFactorySchedulerConfig 类:

@Component
public class MyJobFactory extends SpringBeanJobFactory {@Resourceprivate AutowireCapableBeanFactory beanFactory;@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object jobInstance = super.createJobInstance(bundle);beanFactory.autowireBean(jobInstance);  // 注入 Spring 管理的依赖return jobInstance;}
}@Configuration
public class SchedulerConfig {@Resourceprivate MyJobFactory myJobFactory;@Beanpublic SchedulerFactoryBean schedulerFactoryBean(@Qualifier("dataSource") DataSource dataSource) throws IOException {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setDataSource(dataSource);factory.setJobFactory(myJobFactory);  // 配置 JobFactory,注入 Spring Beanfactory.setStartupDelay(2);  // 延迟启动调度器return factory;}
}

通过这种方式,我们可以确保 Quartz 任务的执行能够访问到 Spring 容器中的所有 Bean。

4. 创建任务调度接口

创建一个 JobController 来操作定时任务的增加、暂停、恢复、删除等操作。以下是增强后的 JobController 类:

@RestController
@RequestMapping(value = "/admin/job")
public class JobController {private static Logger LOG = LoggerFactory.getLogger(JobController.class);@Autowiredprivate SchedulerFactoryBean schedulerFactoryBean;@RequestMapping(value = "/add")public CommonResp add(@RequestBody CronJobReq cronJobReq) {String jobClassName = cronJobReq.getName();String jobGroupName = cronJobReq.getGroup();String cronExpression = cronJobReq.getCronExpression();String description = cronJobReq.getDescription();LOG.info("创建定时任务开始:{},{},{},{}", jobClassName, jobGroupName, cronExpression, description);CommonResp commonResp = new CommonResp();try {Scheduler sched = schedulerFactoryBean.getScheduler();sched.start();  // 启动调度器JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(jobClassName)).withIdentity(jobClassName, jobGroupName).build();CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName).withDescription(description).withSchedule(scheduleBuilder).build();sched.scheduleJob(jobDetail, trigger);} catch (SchedulerException | ClassNotFoundException e) {LOG.error("创建定时任务失败:" + e);commonResp.setSuccess(false);commonResp.setMessage("创建定时任务失败: " + e.getMessage());}LOG.info("创建定时任务结束:{}", commonResp);return commonResp;}// 其他接口:run、pause、resume、delete等
}

5. 请求参数和返回结果

请求参数 CronJobReq 类:

public class CronJobReq {private String group;private String name;private String description;private String cronExpression;// Getter 和 Setter 方法
}

返回结果 CronJobResp 类:

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class CronJobResp {private String group;private String name;private String description;private String state;private String cronExpression;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date nextFireTime;@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date preFireTime;// Getter 和 Setter 方法
}

6. 测试接口

你可以使用以下 HTTP 请求来测试定时任务的创建:

POST http://localhost:8000/admin/job/add
Content-Type: application/json{"name": "com.stu.train.batch.job.TestJob","group": "default","cronExpression": "*/2 * * * * ?","description": "Test job"
}

通过上述步骤,Quartz 将会将调度任务的信息保存到数据库中,确保任务的持久化管理和恢复。

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

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

相关文章

redis linux 安装

下载解压 https://download.redis.io/releases/ tar -zvxf ----redis-7.4.1编译 进入目录下 # redis 依赖c yum install gcc-cmake可能会有问题&#xff0c;所以记得换源# 安装到 /usr/local/redis make PREFIX/usr/local/redis installcd src ./redis-serverredis.confi…

C语言编程练习:验证哥德巴赫猜想 进制转换 rand函数

目录 一. 验证哥德巴赫猜想 二. 进制转换 三. rand函数 往期回顾 一. 验证哥德巴赫猜想 任一充分大的偶数&#xff0c;可以用两个素数之和表示&#xff0c;例如&#xff1a; 4 2 2 6 3 3 10 3 7 10 5 5 .. 9 8 1 9 7 9 • 思路&#xff1a;偶数 num 是要分解的数&…

npm list -g --depth=0(用来列出全局安装的所有 npm 软件包而不显示它们的依赖项)

您提供的命令 npm list -g --depth0 是在 Node Package Manager (npm) 的上下文中使用的&#xff0c;用来列出全局安装的所有 npm 软件包而不显示它们的依赖项。 这是它的运作方式&#xff1a; npm list -g --depth0-g: 指定列表应包括全局安装的软件包。--depth0: 限制树形结…

‘视’不可挡:OAK相机助力无人机智控飞行!

南京邮电大学通达学院的刘同学用我们的oak-d-lite实现精确打击无人机的避障和目标识别定位功能&#xff0c;取得了比赛冠军。我们盼望着更多的朋友们能够加入到我们OAK的队伍中来&#xff0c;参与到各式各样的比赛中去。我们相信&#xff0c;有了我们相机的助力&#xff0c;大家…

hive 统计各项目下排名前5的问题种类

实现指定某项目下的数据效果图如下所示&#xff1a; 其中 ABCDE 为前5名的问题种类&#xff0c;其中A问题有124个&#xff08;出现了124次&#xff09; 数据说明&#xff1a; 整个数据集 包含很多项目一个项目 包含很多问题一个问题 选项 可认为是 类别值&#xff0c;所有出…

Odoo :一款免费开源的日化行业ERP管理系统

文 / 开源智造Odoo亚太金牌服务 概述 构建以 IPD 体系作为核心的产品创新研发管控体系&#xff0c;增进企业跨部门业务协同的效率&#xff0c;支撑研发管控、智慧供应链、智能制造以及全渠道营销等行业的场景化&#xff0c;构筑行业的研产供销财一体化管理平台。 行业的最新…

nacos-operator在k8s集群上部署nacos-server2.4.3版本踩坑实录

文章目录 操作步骤1. 拉取仓库代码2. 安装nacos-operator3. 安装nacos-server 坑点一坑点二nacos-ui页面访问同一集群环境下微服务连接nacos地址配置待办参考文档 操作步骤 1. 拉取仓库代码 &#xff08;这一步主要用到代码中的相关yml文件&#xff0c;稍加修改用于部署容器&…

【安全科普】NUMA防火墙诞生记

一、我为啥姓“NUMA” 随着网络流量和数据包处理需求的指数增长&#xff0c;曾经的我面对“高性能、高吞吐、低延迟”的要求&#xff0c;逐渐变得心有余而力不足。 多CPU技术应运而生&#xff0c;SMP&#xff08;对称多处理&#xff09;和NUMA&#xff08;非一致性内存访问&a…

HarmonyOS Next 组件或页面之间的所有通信(传参)方法总结

系列文章目录 【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器&#xff08;上&#xff09; 【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器&#xff08;下&#xff09; 【鸿蒙】HarmonyOS NEXT应用开发快速入门教程之布局篇&#xff08;上&#xff09; 【…

LeetCode654.最大二叉树

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路⌨C代码 &#x1f4dc;题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子…

电子应用产品设计方案-9:全自动智能马桶系统设计方案

一、系统概述 本全自动智能马桶系统旨在提供舒适、卫生、便捷和智能化的如厕体验。通过融合多种传感器技术、电子控制单元和机械执行机构&#xff0c;实现马桶的自动冲洗、座圈加热、臀部清洗、烘干等功能&#xff0c;并具备智能感应、用户个性化设置和健康监测等特色功能。 二…

酒水分销积分商城小程序开发方案php+uniapp

酒水分销积分商城小程序开发&#xff0c;开发语言后端php&#xff0c;前端uniapp。核心功能模块&#xff1a;酒水商城、积分商城、二级分销、抽奖、优惠券。可以二开或定制。协助部署搭建。

UNIX网络编程-TCP套接字编程(实战)

概述 TCP客户端/服务器程序示例是执行如下步骤的一个回射服务器&#xff1a; 客户端从标准输入读入一行文本&#xff0c;并写给服务器。服务器从网络输入读入这行文本&#xff0c;并回射给客户端。客户端从网络输入读入这行回射文本&#xff0c;并显示在标准输出上。 TCP服务器…

Kafka-Eagle的配置——kafka可视化界面

通过百度网盘分享的文件&#xff1a;kafka-eagle-bin-2.0.8.tar.gz 链接&#xff1a;https://pan.baidu.com/s/1H3YONkL97uXbLTPMZHrfdg?pwdsltu 提取码&#xff1a;sltu 一、界面展示 二、软件配置 1、关闭kafka集群 kf.sh stop 2、将该软件上传到/opt/modules下 cd /opt…

Uniapp踩坑input自动获取焦点ref动态获取实例不可用

前言 大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识。很久很更新了&#xff0c;这几个月一直在加班&#xff0c;今天记录一个uniapp关于input中focus()方法自动获取焦点的坑。 案例 为了实现一个手机验证码的页面&#xff0c;验证码是五个输入框&#xf…

报错 No available slot found for the embedding model

报错内容 Server error: 503 - [address0.0.0.0:12781, pid304366] No available slot found for the embedding model. We recommend to launch the embedding model first, and then launch the LLM models. 目前GPU占用情况如下 解决办法: 关闭大模型, 先把 embedding mode…

AI大模型(二):AI编程实践

一、软件安装 1. 安装 Visual Studio Code VSCode官方下载&#xff1a;Visual Studio Code - Code Editing. Redefined 根据自己的电脑系统选择相应的版本下载 安装完成&#xff01; 2. 安装Tongyi Lingma 打开VSCode&#xff0c;点击左侧菜单栏【extensions】&#xff0c;…

MFC程序崩溃时生成dmp文件

#include “HiExceptionHandle.h” #include <string> #pragma once class HiExceptionHandle { public:HiExceptionHandle(void);~HiExceptionHandle(void); public:void RunCrashHandler();void SetWERDumpLocation(const std::wstring dumpFolderPath); protected:st…

释放高级功能:Nexusflows Athene-V2-Agent在工具使用和代理用例方面超越 GPT-4o

在不断发展的人工智能领域&#xff0c;Nexusflows 推出了 Athene-V2-Agent 作为其模型系列的强大补充。这种专门的代理模型设计用于在功能调用和代理应用中发挥出色作用&#xff0c;突破了人工智能所能达到的极限。 竞争优势 Athene-V2-Agent 不仅仅是另一种人工智能模型&…

Flutter:input输入框

输入框&#xff1a; // 是否显示关闭按钮 bool _showClear false; // 文字编辑控制器&#xff0c;监听搜索框的变化。 final TextEditingController _controller TextEditingController(); // 输入框发生变化事件 void _onChange(String value){if(value.length > 0){setS…