开发基础
开发基础笔记
mybatis-plus通用的service方法
通过jenkins配置前后端自动打包及发布
mybatis-plus实现分页的方式
Java极客技术公众号PDF
狂神说SpringBoot
Hashids java 版使用
SpringBoot
1、Web快速开发
2、结果集的封装
3、集成MyBatis实现数据库操作
4、Springboot @Validated参数校验
5、SpringBoot全局异常处理
6、拦截器HandlerInterceptor
7、集成Swagger实现API自动生成
8、集成knife4j实现API自动生成
9、Springboot集成MyBatis-Plus快速入门
10、springboot自定义注解及AOP切面使用
11、使用Shiro实现登陆和权限认证,基于MyBatis
12、集成SpringSecurity实现授权认证
13、SpringBoot集成EasyExcel实现数据导入与导出
14、Spring Task定时任务的实现
15、Quartz快速上手与实践
16、如何用代码实现Spring IOC
17、SpringBoot集成JWT,实现接口的鉴权交互
SpringCloud
Nacos作为服务注册中心
seata1.6.1 结合springcloud实现分布锁的技术笔记
一些技术博客推荐
前端面试相关
看这一篇就够了
java.util包常用的类和接口
CountDownLatch介绍与使用
Common-lang3使用入门
Hutool简单使用入门
lombok 介绍及基本使用方法
git项目统计成员代码行数和提交的次数
mysql 逗号分隔的数据 like查询
使用sonar进行代码质量检查
线上使用jmeter进行压测的时候,使用Arthas诊断工具排查响应慢的接口
php结合phpstudy8、vscode开启xdebug进行代码调试
node-red使用入门
本文档使用 MrDoc 发布
-
+
首页
15、Quartz快速上手与实践
上手Quartz有一段时间,对相关知识做了个总结 。 任务调度框架,除了Quartz外,还有springboot框架自家的scheduled,xxljob 选择Quartz的目地主要有两点,可动态控制调度任务、灵活性、集群 ### 1、Quartz的体系结构  ### 2、几个重要的概念 **Scheduler** 用于与调度程序交互的主程序接口,通过调度器,将jobDetail与Trigger 关联起来, **Job** 自定义一个任务类,继承 这个接口,实现execute方法,在这个方法里写你的业务逻辑。比如生成报表、数据抽取等 **JobDetail** 使用JobDetail来定义定时任务的实例,JobDetail实例是通过JobBuilder类创建的。 **Trigger** 触发器,Trigger对象是用来触发执行job的 **JobDataMap** 可以包含不限量的(序列化的)数据对象,在iob实例执行的时候,可以使用其中的数据。JobDataMap是Java Map接口的一个实现 **JobBuilder** 用来生成 JobDetail **TriggerBuilder** 用来生成Trigger **JobListener**、**TriggerListener**、**SchedulerListener** 监听器,用于对组件的监听 ### 3、简单上手 下面的示例全部使用springboot集成的方式去使用。 引入坐标: ~~~xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ~~~ #### 3.1 实现Job接口,或者QuartzJobBean接口也行 以下是 Task1Job.java任务类的代码。 ~~~java @DisallowConcurrentExecution public class Task1Job extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { // 从Job获取数据 JobDetail jobDetail = context.getJobDetail(); String value = jobDetail.getJobDataMap().getString("key"); String parameter = jobDetail.getJobDataMap().getString("parameter"); String description = jobDetail.getDescription(); // 从Trigger获取数据 Trigger trigger = context.getTrigger(); String value2 = trigger.getJobDataMap().getString("key"); String parameter2 = trigger.getJobDataMap().getString("parameter"); String description2 = trigger.getDescription(); } } ~~~ #### 3.2 添加一个调度任务 不管是JobDetail还是CronTrigger、甚至是Scheduler,都可以 在添加任务的时候,通过usingJobData和getJobDataMap().putAll 两种方式附加参数,并且他俩都自带了Description这个字段值 ,在数据表中可以看到,都可以通过withDescription方法 添加描述的信息。 withIdentity方法一般通过传入jobName和jobGroupName两个参数来 标识 他的唯一性,我这里直接把jobGroupName参数给忽略了,默认系统会 指定jobGroupName=DEFAULT 每个JobDetail通过JobBuilder.newJob方法 绑定一个 具体的任务实现类。 核心代码如下: ~~~java // 附加数据,可以是任意类型的业务数据 HashMap<String, Object> jobData = new HashMap<>(); jobData.put("parameter", "hello world"); // jobDetail JobDetail jobDetail = JobBuilder.newJob(Task1Job.class) .usingJobData("key", "job-value") .withDescription("一段任务的描述") .withIdentity("cronJob22").build(); // 数据附加到jobDetail jobDetail.getJobDataMap().putAll(jobData); // 开始时间 3秒钟之后 (具体时间按实际业务编写) Date sData = new Date(); sData.setTime(sData.getTime()+3000); // 结束时间 60秒钟之后 (具体时间按实际业务编写) Date eData = new Date(); eData.setTime(eData.getTime()+60000); // 每5秒触发一次任务 CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("cronTrigger22") .withDescription("一段触发器的描述") .startAt(sData) //设定开始时间 .endAt(eData) //设定结束时间 .usingJobData("key", "trigger-value") // 附加数据 .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")) .build(); // 数据附加到cronTrigger cronTrigger.getJobDataMap().putAll(jobData); // Scheduler实例 StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = stdSchedulerFactory.getScheduler(); // 将任务与触发器注册到任务调度中 scheduler.scheduleJob(jobDetail,cronTrigger); // 启动 scheduler.start(); ~~~ #### 3.3 quartz的11张表  通过数据库方式实现的调度任务,一般quartz系统里用到这11张表,没有必要可以不用做深入的了解。 一般建议用户把上面的这11张表 ,做为一个单独的库进行保存,以提升性能。 所以涉及的业务数据库和quartz库 建议独立分开。 任务的基本信息保存在自己的的任务表中,比如我们可以 建一张task表用来 维护任务状态和cron表达式之类的。 **对task进行增删改查的时候,同时调用quartz的相关接口,同步任务的调度状态。** 一般情况下,jobDetail和trigger 是一一对应的关系。每个jobDetail都是由单独的触发器去 出发执行。 这样的设计是考虑到了 jobDetail的复用,试想一下,如果触发器到期了,quartz是连带job一起删除掉。 但是有时候你想保留jobDetail,在未来的某个时间点 给这个jobDetail重新绑定一个新的 trigger触发器。 还有一个场景是,一个jobDetail可以被 多个trigger触发器绑定,但是一个trigger触发器只能绑定一个jobDetail,不能绑定多个jobDetail!!! 接下来演示一下代码。 #### 3.4 一个jobDetail可以被 多个trigger触发器绑定 ~~~java //jobDetail JobDetail jobDetail = JobBuilder.newJob(Task1Job.class) .withIdentity("job1") .storeDurably() .withDescription("任务描述11") .usingJobData("key", "job10") .build(); //开始时间 3秒钟之后 (具体时间按实际业务编写) Date sData = new Date(); sData.setTime(sData.getTime()+3000); //结束时间 60秒钟之后 (具体时间按实际业务编写) Date eData = new Date(); eData.setTime(eData.getTime()+60000); //每5秒触发任务 CronTrigger cronTrigger = newTrigger() .withIdentity("trigger1") .withDescription("CronTrigger") .startAt(sData) //设定开始时间 .endAt(eData) //设定结束时间 .forJob(jobDetail) .usingJobData("key", "c-trigger10") // 附加数据 .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")).build(); SimpleTrigger simpleTrigger = newTrigger() .withIdentity("trigger2") .withDescription("simpleTrigger") .startAt(sData) //设定开始时间 .endAt(eData) //设定结束时间 .forJob(jobDetail) .usingJobData("key", "s-trigger10") // 附加数据 .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build(); // 获取Scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.addJob(jobDetail, true); scheduler.scheduleJob(cronTrigger); scheduler.scheduleJob(simpleTrigger); scheduler.start(); ~~~ 这里使用到了两个触发器: CronTrigger 和 SimpleTrigger 这是quartz里最常用的两个触发器,这两个触发器通过 forJob(jobDetail) 方法,自行绑定了 JobDetail实例。 通过 withSchedule 方法,各自绑定 相应的的的运行规则 CronTrigger是 每5秒调度一个。 SimpleTrigger使用: ~~~java SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever() ~~~ 代码每2秒运行一次,一直重复不停,虽然 这里使用了 repeatForever 设置了这是一个 重复不停的 运行规则 ,但是该规则 受限于 SimpleTrigger本身的endAt方法,endAt权重高于 repeatForever ,任务会在 eData的时候 准备停止删除! 注意一下上面的第4行代码,storeDurably(),如果不加这一行,会报错: ~~~ org.quartz.SchedulerException: Jobs added with no trigger must be durable. ~~~ 试想一下,如果一个 JobDetail被 两个trigger触发器调用的话,第一个触发器先执行完成之后,正常情况会把关联的jobDetail一起删除掉,这必然会影响到 另一个 触发器的正常运行,所以通过 storeDurably() 将这个JobDetail永久的持久化到数据库,哪怕是触发器已经过期了。
superadmin
2023年9月21日 10:31
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码