定时任务调动框架Quartz+SpringBoot集成

Quartz 是一个基于 Java 的广泛使用的开源的任务调度框架

官网:
http://www.quartz-scheduler.org/

源码:
https://github.com/quartz-scheduler/quartz

整个 Quartz 的代码流程基本基本如下:

1、首先需要创建我们的任务(Job),比如取消订单、定时发送短信邮件之类的,这是我们的任务主体,也是写业务逻辑的地方

2、创建任务调度器(Scheduler),这是用来调度任务的,主要用于启动、停止、暂停、恢复等操作,也就是那几个api的用法

3、创建任务明细(JobDetail),最开始我们编写好任务(Job)后,只是写好业务代码,并没有触发,这里需要用JobDetail来和之前创建的任务(Job)关联起来,便于执行。

4、创建触发器(Trigger),触发器是来定义任务的规则的,比如几点执行,几点结束,几分钟执行一次等等。这里触发器主要有两大类(SimpleTrigger和CronTrigger)

5、根据Scheduler来启动JobDetail与Trigger

一、依赖:

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

二、创建Job

JobExecutionContext来获取JobDetail或者Trigger传入的参数进行处理

/**
	例如任务的执行时间过长,而每次触发的时间间隔太短,则会导致任务会被并发执行。如果是并发执行,就需要一个数据库锁去避免一个数据被多次处理。
*/
@DisallowConcurrentExecution//Job中的任务有可能并发执行。
public class TestJob implements Job{
	
	@Override
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		
		System.err.println(jobExecutionContext.getJobDetail().getJobDataMap().get("name"));
        System.err.println(jobExecutionContext.getJobDetail().getJobDataMap().get("age"));
        System.err.println(jobExecutionContext.getTrigger().getJobDataMap().get("orderNo"));
        System.err.println("定时任务执行,当前时间:"+ DateUtil.formatDateTime(new Date()));
	}
}

三、创建任务调度器(Scheduler)

Spring IOC,所以直接注入完事。如果是普通的,则需通过工厂创建

①、工厂:

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();

②、IOC:

@Autowired
private Scheduler scheduler;

四、创建任务明细

/**
	通过JobBuilder.newJob()方法获取到当前Job的具体实现(以下均为链式调用)
 * 这里是固定Job创建,所以代码写死XXX.class
 * 如果是动态的,根据不同的类来创建Job,则 ((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass()
 * 即是 JobBuilder.newJob(((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass())

*/
JobDetail jobDetail = JobBuilder.newJob(TestJob.class)//获取当前Job具体实现
	.usingJobData("name","jordan")
	.usingJobData("age",23)
	.withIdentity("我是name","我是group")//添加认证信息(有3种重写方式)
	.build();

五、创建触发器

主要分为两大类SimpleTrigger、CronTrigger

  • SimpleTrigger:是根据它自带的api方法设置规则,比如每隔5秒执行一次、每隔1小时执行一次
  • CronTrigger:这就比较常用了,是基于Cron表达式来实现的
Trigger trigger = TriggerBuilder.newTrigger()
	.usgingJobData("orderNo","1234")
	.withIdentity("我是name","我是group")
	//.startNow 立即生效
	.startAt(start) //开始执行时间
	.endAt(start)//结束执行时间
	.withSchedule( //添加执行规则,SimpleTrigger、CronTrigger的区别主要就在这里
		SimpleScheduleBuilder.simpleSchedule()
		.withIntervalInSeconds(3)//每隔3s执行一次,api方法有好多规则自行查看
		.repeatForever()//一直执行,如果不写,定时任务就执行一次
	)
	.build();//执行
CronTrigger trigger = TriggerBuilder.newTrigger()
	.usingJobData("orderNo","1234")
	.withIdentity("我是name","我是group")
	 /**立即生效*/
//      .startNow()
     /**开始执行时间*/
     .startAt(start)
     /**结束执行时间,不写永久执行*/
     .endAt(start)
     .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?"))
     .build();

【.startNow( )和.startAt( )这里有个坑,这两个方法是对同一个成员变量进行修改的 也就是说startAt和startNow同时调用的时候任务开始的时间是按后面调用的方法为主的,谁写在后面用谁】

六、启动任务

/**添加定时任务*/
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
    /**启动*/
    scheduler.start();
}

以上,任务的创建启动都完事了,后面就是任务的暂停、恢复、删除。比较简单,大致原理就是我们在创建任务明细(JobDetail)和创建触发器(Trigger)时,会调用.withIdentity(key,group)来传入认证信息,后续就是根据这些认证信息来管理任务(通过api方法)

七、任务暂停

scheduler.pauseTrigger(TriggerKey.triggerKey("我是刚才写的name","我是刚才写的group"));

八、任务的恢复

scheduler.resumeTrigger(TriggerKey.triggerKey("我是刚才写的name","我是刚才写的group"));

在这里插入图片描述
根据方法来获取

九、任务的删除

scheduler.pauseTrigger(TriggerKey.triggerKey("我是刚才写的name","我是刚才写的group"));//暂停触发器
scheduler.unscheduleJob(TriggerKey.triggerKey("我是刚才写的name","我是刚才写的group"));//移除触发器
scheduler.deleteJob(JobKey.jobKey("我是刚才写的name","我是刚才写的group"));//删除Job

如果想让定时任务在启动项目后自动启动,则需要持久化任务,可以把基本信息保存在数据库,项目启动时启动完,或者做分布式任务

 @Autowired
    private Scheduler scheduler;
 
    @PostMapping("/Quartz")
    @ApiOperation(value = "定时任务_创建", notes = "创建")
    @ResponseBody
    public Object quartz(@RequestParam("orderNo")  String orderNo) throws Exception {
        Date start=new Date(System.currentTimeMillis() + 7 * 1000);//当前时间7秒之后
 
        /**通过JobBuilder.newJob()方法获取到当前Job的具体实现(以下均为链式调用)
         * 这里是固定Job创建,所以代码写死XXX.class
         * 如果是动态的,根据不同的类来创建Job,则 ((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass()
         * 即是 JobBuilder.newJob(((Job)Class.forName("com.zy.job.TestJob").newInstance()).getClass())
         * */
        JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
                /**给当前JobDetail添加参数,K V形式*/
                .usingJobData("name","zy")
                /**给当前JobDetail添加参数,K V形式,链式调用,可以传入多个参数,在Job实现类中,可以通过jobExecutionContext.getJobDetail().getJobDataMap().get("age")获取值*/
                .usingJobData("age",23)
                /**添加认证信息,有3种重写的方法,我这里是其中一种,可以查看源码看其余2种*/
                .withIdentity(orderNo)
                .build();//执行
 
 
        Trigger trigger = TriggerBuilder.newTrigger()
                /**给当前JobDetail添加参数,K V形式,链式调用,可以传入多个参数,在Job实现类中,可以通过jobExecutionContext.getTrigger().getJobDataMap().get("orderNo")获取值*/
                .usingJobData("orderNo", orderNo)
                /**添加认证信息,有3种重写的方法,我这里是其中一种,可以查看源码看其余2种*/
                .withIdentity(orderNo)
                /**立即生效*/
//      .startNow()
                /**开始执行时间*/
                .startAt(start)
                /**结束执行时间*/
//        .endAt(start)
                /**添加执行规则,SimpleTrigger、CronTrigger的区别主要就在这里*/
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                /**每隔1s执行一次*/
                                .withIntervalInSeconds(3)
                                /**一直执行,*/
                                .repeatForever()
                )
                .build();//执行
 
//CronTrigger  trigger = TriggerBuilder.newTrigger()
//        /**给当前JobDetail添加参数,K V形式,链式调用,可以传入多个参数,在Job实现类中,可以通过jobExecutionContext.getTrigger().getJobDataMap().get("orderNo")获取值*/
//        .usingJobData("orderNo", orderNo)
//        /**添加认证信息,有3种重写的方法,我这里是其中一种,可以查看源码看其余2种*/
//        .withIdentity(orderNo)
//        /**开始执行时间*/
//        .startAt(start)
//        /**结束执行时间*/
//        .endAt(start)
//        /**添加执行规则,SimpleTrigger、CronTrigger的区别主要就在这里*/
//        .withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
//        .build();//执行
 
 
        /**添加定时任务*/
        scheduler.scheduleJob(jobDetail, trigger);
        if (!scheduler.isShutdown()) {
            /**启动*/
            scheduler.start();
        }
        System.err.println("--------定时任务启动成功 "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+" ------------");
        return "ok";
    }
 
    @PostMapping("/shutdown")
    @ApiOperation(value = "定时任务_停止", notes = "停止")
    @ResponseBody
    public Object shutdown(@RequestParam("orderNo")  String orderNo) throws IOException, SchedulerException {
        scheduler.pauseTrigger(TriggerKey.triggerKey(orderNo));//暂停Trigger
        return "";
    }
 
    @PostMapping("/resume")
    @ApiOperation(value = "定时任务_恢复", notes = "恢复")
    @ResponseBody
    public Object resume(@RequestParam("orderNo")  String orderNo) throws IOException, SchedulerException {
        scheduler.resumeTrigger(TriggerKey.triggerKey(orderNo));//恢复Trigger
        return "ok";
    }
 
    @PostMapping("/del")
    @ApiOperation(value = "定时任务_删除", notes = "删除")
    @ResponseBody
    public Object del(@RequestParam("orderNo")  String orderNo) throws IOException, SchedulerException {
        scheduler.pauseTrigger(TriggerKey.triggerKey(orderNo));//暂停触发器
        scheduler.unscheduleJob(TriggerKey.triggerKey(orderNo));//移除触发器
        scheduler.deleteJob(JobKey.jobKey(orderNo));//删除Job
        return "ok";
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【重要公告】BSV区块链协会宣布将启动多项动态安全增强措施

​​发表时间&#xff1a;2024年2月16日 2024年2月16日&#xff0c;瑞士楚格 - BSV区块链协议的管理机构BSV区块链协会&#xff08;以下简称“BSV协会”&#xff09;宣布对其运营模式实施全新的安全架构&#xff0c;其中包括引入网络访问规则和数字资产找回协议&#xff0c;以及…

【Go语言】Go语言中的字典

Go语言中的字典 字典就是存储键值对映射关系的集合&#xff0c;在Go语言中&#xff0c;需要在声明时指定键和值的类型&#xff0c;此外Go语言中的字典是个无序集合&#xff0c;底层不会按照元素添加顺序维护元素的存储顺序。 如下所示&#xff0c;Go语言中字典的简单示例&…

Linux系统Docker部署Nexus Maven并实现远程访问本地管理界面

文章目录 1. Docker安装Nexus2. 本地访问Nexus3. Linux安装Cpolar4. 配置Nexus界面公网地址5. 远程访问 Nexus界面6. 固定Nexus公网地址7. 固定地址访问Nexus Nexus是一个仓库管理工具&#xff0c;用于管理和组织软件构建过程中的依赖项和构件。它与Maven密切相关&#xff0c;可…

如果大数据中多头借贷风险严重怎么办呢?

在大数据报告中&#xff0c;多头借贷风险、逾期风险、联系人风险、司法风险等是大数据评分评级的重要组成部分&#xff0c;大数据多头借贷风险也是很多银行和金融平台比较看重的&#xff0c;那如果大数据中多头借贷风险严重怎么办呢?本文详细为大家讲讲。 大数据多头风险是什么…

Niginx介绍和安装使用

Nginx是什么&#xff1f; Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;第一…

代码随想录算法训练营第二十一天|530.二叉搜索树的最小绝对差、 501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 题目链接/文章讲解&#xff1a; 代码随想录 视频讲解&#xff1a;二叉搜索树中&#xff0c;需要掌握如何双指针遍历&#xff01;| LeetCode&#xff1a;530.二叉搜索树的最小绝对差_哔哩哔哩_bilibili 1.方法1 1.1分析及思路 了解到差值最小的数…

DevEco Studio下载与安装(Windows)

下载地址&#xff1a; HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 安装时直接点击 next 即可。 运⾏已安装的DevEco Studio&#xff0c;⾸次使⽤&#xff0c;请选择Do not import settings&#xff0c;单击OK。 1.安装Node.js 如果本地有下载&#xff0c;可以…

C程序的编译过程

目录 一、GCC编译器 二、编译过程 1、预处理&#xff08;Preprocessing&#xff09; 2、编译&#xff08;Compilation&#xff09; 3、汇编&#xff08;Assembly&#xff09; 4、链接&#xff08;Linking&#xff09; 三、秋招真题演练 一、GCC编译器 在这里&#xf…

linux系统Jenkins工具web配置

Jenkins工具配置 插件配置系统配置系统工具配置 插件配置 下载 Maven Integration Pipeline Maven lntegration gitlab Generic webhook Trigger nodejs Blue ocean系统配置 系统配置结束系统工具配置

androidframework开发面试,阿里P8成长路线

字节跳动Android面经 一面问的 Java 和 Android 基础 1、Jvm虚拟机 2、messageQueue会不会阻塞ui线程 3、对象锁和类锁 4、之字形打印树 5、还有其他的 《Android学习笔记总结最新移动架构视频大厂安卓面试真题项目实战源码讲义》 **完整开源项目&#xff1a;docs.qq.com/doc…

Linux命名管道

Linux匿名管道-CSDN博客 目录 1.原理 2.接口实现 3.模拟日志 Linux匿名管道-CSDN博客 这上面叫的是匿名管道&#xff0c;不要将两者搞混&#xff0c;匿名管道说的是两个有血缘关系的进程相互通信&#xff0c;但是命名管道就是两个没有关系的管道相互通信。 1.原理 和匿名…

解密犯罪时间 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 警察在侦破一个案件时&#xff0c;得到了线人给出的可能犯罪时间&#xff0c;形如 HH:MM 表示的时刻。 根据警察和线人的约定&#xff0c;为了隐蔽&#xff0c;该…

RabbitMQ实战学习

RabbitMQ实战学习 文章目录 RabbitMQ实战学习RabbitMQ常用资料1、安装教程2、使用安装包3、常用命令4、验证访问5、代码示例 一、RabbitMQ基本概念1.1. MQ概述1.2 MQ 的优势和劣势1.3 MQ 的优势1. 应用解耦2. 异步提速3. 削峰填谷 1.4 MQ 的劣势1.5 RabbitMQ 基础架构1.6 JMS 二…

图形系统开发实战课程:进阶篇(上)——8.图形样式

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形样式”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-8.html 第八章 图形样式 1. 填充和描边 \quad 在图形系统实战…

vision mamba 运行训练记录,解决bimamba_type错误

下载vision mamba github上的项目后&#xff0c;解压&#xff0c;进入文件夹项目&#xff0c;然后配环境 unzip Vim-main.zip cd Vim-mainconda create -n mamba python3.10.13conda activate mamba pip install torch2.1.1 torchvision0.16.1 torchaudio2.1.1 --index-url ht…

java面试(网络)

TCP和UDP有什么区别&#xff1f;TCP三次握手不是两次&#xff1f; TCP&#xff1a;面向连接&#xff0c;可靠的&#xff0c;传输层通信协议。点对点&#xff0c;占用资源多&#xff0c;效率低。 UDP&#xff1a;无连接&#xff0c;不可靠&#xff0c;传输层通信协议。广播&…

照片中不想要的部分怎么去除?教你几个小妙招

照片在我们的生活中占据着无可替代的地位。它们是我们生活的缩影&#xff0c;定格住我们的瞬间&#xff0c;记录着我们的记忆&#xff0c;让我们可以随时随地回顾过去的美好时光。无论是家庭聚会、旅行、婚礼还是其他重要的场合&#xff0c;我们都会用照片来捕捉这些珍贵的时刻…

springboot 实现本地文件存储

springboot 实现本地文件存储 实现过程 上传文件保存文件&#xff08;本地磁盘&#xff09;返回文件HTTP访问服务器路径给前端&#xff0c;进行效果展示 存储 服务端接收上传的目的是提供文件的访问服务&#xff0c;对于SpringBoot而言&#xff0c;其对静态资源访问提供了很…

【Java设计模式】三、

文章目录 0、案例&#xff1a;咖啡屋1、简单工厂模式 静态工厂&#xff08;不属于23种之列&#xff09;2、工厂方法模式3、抽象工厂模式4、建造者模式5、原型设计模式 0、案例&#xff1a;咖啡屋 模拟咖啡店点餐。咖啡有多种&#xff0c;抽象类&#xff0c;子类为各种咖啡。咖…

element ui富文本编辑器的使用(quill-editor)

引用组件 <el-form-item label"内容"><editor v-model"obj.activity_content" :min-height"192"/> </el-form-item> 组件封装 <template><div><el-upload:action"uploadUrl":before-upload"…