1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > Quartz-scheduler 定时器概述 核心 API 与 快速入门

Quartz-scheduler 定时器概述 核心 API 与 快速入门

时间:2024-06-20 18:49:24

相关推荐

Quartz-scheduler 定时器概述 核心 API 与 快速入门

目录

quartz-scheduler 石英调度器概述

quartz-scheduler HelloWorld

quartz-scheduler 核心 API

quartz.properties Quartz Configuration

JobDataMap 任务数据对象

Job/JobDetail 实例 与 并发

MVC 访问调度 Quartz 任务

本文源码:/wangmaoxiong/quartzapp

quartz-scheduler 石英调度器概述

1、Quartz 是功能强大的开源作业调度库,几乎可以集成到任何 Java 应用程序中,从最小的独立应用程序到最大的电子商务系统。Quartz 可用于创建简单或复杂的计划,以执行数以万计的工作;可以执行您编写的所有内容。

2、Quartz Scheduler 包含许多企业级功能,例如对 JTA 事务和集群的支持。Quartz 是免费使用的,并根据 Apache 2.0 许可获得许可。

3、Spring Boot 官方也对 Quartz 调度器进行了集成,Spring boot 官网文档:Quartz Scheduler

4、Java JDK 有原生的计时器 Timer以及 定时执行服务 ScheduledExecutorService ,Spring 也提供了 @Scheduled 执行定时任务。

5、生产中如果定时任务多,处理频繁,则强烈建议使用第三方封装的调度框架,因为定时器操作底层都是多线程的操作,任务的启动、暂停、恢复、删除、实质是线程的启动、暂停、中断、唤醒等操作。

quartz-scheduler HelloWorld

1、本文环境 Spring Boot 2.1.3 + java jdk 1.8 ,pom.xml 文件中导入 quartz 依赖:

<!--quartz 定时器 /artifact/org.springframework.boot/spring-boot-starter-quartz --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId><version>2.2.5.RELEASE</version></dependency>

源码:/wangmaoxiong/quartzapp/blob/master/pom.xml

spring-boot-starter-quartz 组件内部依赖了如下的组件:

2、由浅入深,下面先以一个简单 main 方法调用来介绍 quartz 作业调度器的基本使用步骤。

import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/*** 自定义作业实现 org.quartz.Job 接口,execute 方法中写作业逻辑.*/public class HelloJob implements Job {private static Logger logger = LoggerFactory.getLogger(HelloJob.class);@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {//获取触发器的名称及其组名称,获取作业详细信息的名称及其组名称.String triggerName = context.getTrigger().getKey().getName();String triggerGroup = context.getTrigger().getKey().getGroup();String jobDetailName = context.getJobDetail().getKey().getName();String jobDetailGroup = context.getJobDetail().getKey().getGroup();logger.info("执行作业,作业名称={},作业所属组={},触发器名称={},触发器所属组={}",jobDetailName, jobDetailGroup, triggerName, triggerGroup);}}

import org.quartz.*;import org.quartz.impl.StdSchedulerFactory;public class HelloTest {public static void main(String[] args) throws SchedulerException, InterruptedException {//1)读取 classpath 下的 quartz.properties(不存在就都使用默认值)配置来实例化 Scheduler//可以在类路径下使用同名文件覆盖 quartz-x.x.x.jar 包下的 org\quartz\quartz.properties 属性文件Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();//2、定义作业的详细信息,并设置要执行的作业的类名。设置作业的名称及其组名.JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "jobGroup").build();//3、创建触发器,设置触发器名称与组名称,设置 CronTrigger 触发器的调度规则为每 10 秒触发一次.//startNow():表示立即触发任务,否则需要等待下一个触发点CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("helloTrigger", "triggerGroup").startNow().withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?")).build();//4、将 jobDetail 与 trigger 注册到调度器 scheduler 并启动。scheduler.scheduleJob(jobDetail, cronTrigger);scheduler.start();TimeUnit.MINUTES.sleep(1);//1分钟以后停掉调度器scheduler.shutdown();}}

quartz-scheduler 核心 API

1、Scheduler 实例化后,可以启动(start)、暂停(stand-by)、停止(shutdown)。

2、Scheduler 被停止后,除非重新实例化,否则不能重新启动;只有当 scheduler 启动后,trigger才会被触发(job才会被执行;暂停状态 trigger 不会触发执行任务。

3、Scheduler 生命周期:从 SchedulerFactory 创建它开始,到 Scheduler 调用 shutdown() 方法结束;Scheduler 被创建后,可以增加、删除和列举 Job 和 Trigger,以及执行其它与调度相关的操作(如暂停Trigger)。

4、SimpleTrigger 触发器主要用于一次性执行的 Job(只在某个特定的时间点执行一次),或者每间隔T个时间单位执行一次。CronTrigger 触发器基于日历进行调度,如“每个星期五的正午”,或者“每月的第十天的上午10:15”等。

5、Job 被创建后,可以保存在 Scheduler 中,与 Trigger 是独立的,同一个 Job 可以有多个 Trigger;这种松耦合的一个好处是可以修改或者替换 Trigger,而不用重新定义与之关联的 Job。

6、Job 和 Trigger 注册到 Scheduler 时,可以为它们设置 key,配置其身份属性。Job 和 Trigger 的key(JobKey和TriggerKey)可以用于将 Job 和 Trigger 放到不同的分组(group)里,然后基于分组进行操作。同一个分组下的 Job 或 Trigger 的名称必须唯一,即一个 Job 或 Trigger 的 key 由名称(name)和分组(group)组成。

quartz.properties Quartz Configuration

1、Quartz 使用一个名为 quartz.properties 的属性文件进行信息配置,必须位于 classpath 下,是 StdSchedulerFactory 用于创建 Scheduler 的默认属性文件。

2、默认情况下 StdSchedulerFactory 从类路径下加载名为 “quartz.properties” 的属性文件,如果失败,则加载 org/quartz 包中的“quartz.properties”文件,其默认内容如下:

#计划程序的名称org.quartz.scheduler.instanceName: DefaultQuartzScheduler org.quartz.scheduler.rmi.export: falseorg.quartz.scheduler.rmi.proxy: falseorg.quartz.scheduler.wrapJobExecutionInUserTransaction: falseorg.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool#线程池中的线程个数.10个线程表示最多可以同时执行10个任务/作业org.quartz.threadPool.threadCount: 10org.quartz.threadPool.threadPriority: 5org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: trueorg.quartz.jobStore.misfireThreshold: 60000#表示 quartz 中的所有数据,比如作业和触发器的信息都保存在内存中(而不是数据库中)org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

3、quartz.properties 可用属性的完整配置信息可以参考官网 Quartz Configuration,根据不同的需求,配置分类如下:

Main Configuration (configuration of primary scheduler settings, transactions)Configuration of ThreadPool (tune resources for job execution)Configuration of Listeners (your application can receive notification of scheduled events)Configuration of Plug-Ins (add functionality to your scheduler)Configuration of RMI Server and Client (use a Quartz instance from a remote process)Configuration of RAMJobStore (store jobs and triggers in memory)Configuration of JDBC-JobStoreTX (store jobs and triggers in a database via JDBC)Configuration of JDBC-JobStoreCMT (JDBC with JTA container-managed transactions)Configuration of DataSources (for use by the JDBC-JobStores)Configuration of Database Clustering (achieve fail-over and load-balancing with JDBC-JobStore)Configuration of TerracottaJobStore (Clustering without a database!)

JobDataMap 任务数据对象

1、创建 JobDetail 时,将要执行的 job 的类名传给了 JobDetail,所以 scheduler 就知道了要执行何种类型的 job;每次当scheduler 执行 job 的 execute(…) 方法之前会创建该类的一个新的实例;执行完毕,对该 Job 实例的引用就被丢弃了,实例会被垃圾回收;

2、Job 实现类中必须有一个无参的构造函数(当使用默认的JobFactory时),Job 实现类中,不应该定义有状态的数据属性,因为在 job 的多次执行中,这些属性的值不会保留。应该使用 JobDataMap 给 Job 实例设置属性,用于在多次执行中跟踪 Job 的状态。

3、JobDetail、Trigger 实现类中都定义 JobDataMap 成员变量及其 getter、setter 方法,可以用来设置参数信息,Job 执行 execute() 方法的时候,JobExecutionContext 可以获取到 JobDataMap 中的信息。

import org.quartz.*;import org.quartz.impl.StdSchedulerFactory;/*** @author wangmaoxiong*/public class HiJobTest {public static void main(String[] args) {try {//1)读取 classpath 下的 quartz.properties(不存在就都使用默认值)配置来实例化 SchedulerScheduler scheduler = StdSchedulerFactory.getDefaultScheduler();//2)创建任务详情。设置任务名称与所属组名,同组内的任务名称必须唯一。// 为任务添加数据,可以直接 usingJobData,也可以先 jobDetail.getJobDataMap(),然后 putJobDetail jobDetail = JobBuilder.newJob(HiJob.class).withIdentity("hiJob", "hiJobGroup").usingJobData("url", "https://wangmaoxiong./article/details/105057405").build();//3)设置触发器,设置触发器名称与所属组名,同组内的触发器名称必须唯一。// 为触发器添加数据,可以直接 usingJobData,也可以先 jobDetail.getJobDataMap(),然后 put// startNow() 表示启动后立即执行// withSchedule(ScheduleBuilder<SBT> scheduleBuilder):设置触发器调度计划,withIntervalInSeconds:间隔多少秒执行// repeatForever:表示用于重复。Trigger trigger = TriggerBuilder.newTrigger().withIdentity("hiTrigger", "hiTriGroup").startNow().usingJobData("totalCount", 3).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();//4)注册任务详情与触发器,然后启动scheduler.scheduleJob(jobDetail, trigger);scheduler.start();} catch (SchedulerException e) {e.printStackTrace();}}}

import org.quartz.Job;import org.quartz.JobDataMap;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;/*** @author wangmaoxiong* quartz 任务/作业*/public class HiJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {//getJobDetail() 返回 JobDetail, getTrigger() 返回 Trigger,然后都可以获取自己的 JobDataMap 进行取值或者设值//context.getMergedJobDataMap() 返回的 JobDataMap 包含了 JobDetail 与 getTrigger 设置的所有属性JobDataMap jobDetailDataMap = context.getJobDetail().getJobDataMap();JobDataMap triggerDataMap = context.getTrigger().getJobDataMap();String url = jobDetailDataMap.getString("url");int totalCount = triggerDataMap.getInt("totalCount");}}

示例源码:/wangmaoxiong/quartzapp/tree/master/src/test/java/com/wmx/quartzapp/helloworld

Job/JobDetail 实例 与 并发

1、一个 Job 实现类可以与多个 JobDetail 实例关联(JobDetal 与 Trigger 一对多),每一个 JobDetail 实例都有自己的属性集和 JobDataMap,最后将所有的实例都注册到 scheduler 中。如 "YearEndSettlementJob" 类实现 Job 接口,该 job 实现需要 JobdataMap 传入一个参数,表示年终结算的季度(1-4)。因此可以创建该 job 的多个实例(JobDetail),如 "jobDetail1"、"jobDetail2"、"jobDetail3"、"jobDetail4", 然后将季度"1,2,3,4"作为 JobDataMap 的属性传入。当一个 trigger 被触发时,与之关联的 JobDetail 实例会被加载,JobDetail 引用的 job 类通过配置在 Scheduler 上的 JobFactory 进行初始化,然后尝试调用 JobDataMap 中的 key 的 setter 方法注入属性值。、

2、Job 的状态数据(JobDataMap)和并发性会被下面两个注解所影响:

3、生产环境如果任务执行存在并发问题,则强烈建议加上 @PersistJobDataAfterExecution 、@DisallowConcurrentExecution 注解,因为当同一个 JobDetail 实例被并发执行时,由于竞争,JobDataMap 中存储的数据很可能是不确定的。

4、当任务的执行时间过长,而触发的时间间隔小于执行时间,则会导致同一个JobDetil 实例被并发执行。所以如果想要验证注解非常简单,只要将执行间隔缩小,然后 Job 实现类的 execute 方法中使用 Thread.sleep() 硬性延迟。查看任务执行情况,然后加上上面的注解才查看。源码如下:

5、通过 JobDetail 对象还可以给 job 实例配置的以下属性:

//2)创建任务详情。设置任务名称与所属组名,同组内的任务名称必须唯一。// 为任务添加数据,可以直接 usingJobData,也可以先 jobDetail.getJobDataMap(),然后 putJobDetail jobDetail = JobBuilder.newJob(HiJob.class).withIdentity("hiJob", "hiJobGroup").usingJobData("url", "https://wangmaoxiong./article/details/105057405").requestRecovery(true) //设置 job 遇到故障重启后,是否是可恢复的,默认为 false..storeDurably(true)//设置 job 是否是持久性的,默认为 false..build();

MVC 访问调度 Quartz 任务

1、为了学习 Quartz 方便,所以使用了 mian 运行,其实对于 web 应用操作步骤完全同理,如下源码所示:

/wangmaoxiong/quartzapp/tree/master/src/main/java/com/wmx/quartzapp

2、其中 WeatherController 控制层提供访问接口,方法中使用 Quartz 调度器调度 WeatherRequestJob 作业,用于定时请求天气信息接口,获取城市的天气数据。

3、WeatherRequestJob 任务中使用 BeanFactoryAware 的方式获取 Spring 容器中的 RestTemplate 实例,然后请求 http 地址.

4、BeanConfig 类是 @Configuration 配置类,使用 @Bean 将 RestTemplate 实例交由 Spring 容器管理.

5、控制层接口返回的数据使用 ResultData 对象进行封装,包含 code、message、data 三部分,同时提供 ResultCode 枚举提供常用的返回值类型。

本文介绍的是内存存储,即所有的调度信息全部存储在内存中,如果需要使用 jdbc 存储到数据库中,则可以参考《Spring Boot 2.1.3 集成 Quartz 定时器, jdbc 持久化调度信息》

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。