百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

任务调度框架Quartz快速入门(好用任务调度框架)

ccwgpt 2024-09-18 12:26 29 浏览 0 评论

Quartz是什么

Quartz是一个功能强大的开源任务调度库,几乎可以集成到任何Java应用程序中,无论是超小型的独立应用还是超大型电子商务系统。

它常用于企业级应用中:

  • Driving Process Workflow:当新订单下达,可以安排一个30分钟内触发的任务,检查订单状态。
  • System Maintenance:安排每个工作日晚上11点将数据库内容转储到文件的任务。
  • Providing reminder services:提供提醒服务。

Quartz还支持集群模式和对JTA服务。

Quartz中的重要API及概念

http://www.quartz-scheduler.org/documentation/quartz-2.2.2/tutorials/

超重要API

  • Scheduler 和调度程序交互的主要API生命周期从SchedulerFactoru创建它开始,到调用shutdown方法结束。一旦Scheduler创建,任何关于scheduling相关的事,他都为所欲为:添加、删除、列出所有的Jobs和triggers、暂停触发器等。在start方法之前,不会做任何事情。
  • Job 你希望被调度器调度的任务组件接口。当Job的触发器触发时,调度程序的工作线程将调用execute方法。该方法接收一个JobExecutionContext对象,为Job实例提供了丰富的运行时环境信息,比如:scheduler、trigger、jobDataMap、job、calendar、各种time等。
  • JobDetail 用于定义任务。JobDetail对象由Quartz客户端在将job加入Scheduler提供,也就是你的程序。它包含了不同为job设置的属性,还有可以用来为job储存状态信息的JobDataMap。注意它和Job的区别,它实际上是Job实例的属性。【Job定义如何执行,JobDetail定义有何属性】
  • Trigger 触发任务执行。触发器可能具有与之关联的JobDataMap,以便于将特定于触发器触发的参数传递给Job。Quartz提供了几种不同的触发器,SimpleTrigger和CronTrigger比较常用。如果你需要一次性执行作业或需要在给定的时间触发一个作业并重复执行N次且有两次执行间有延时delay,SimpleTrigger较为方便。如果你希望基于类似日期表触发执行任务,CronTrgger推荐使用。
  • JobBuilder 用于构建JobDetail的。
  • TriggerBuilder 用于构建Trigger的。

Quartz提供了各种各样的Builder类,定义了Domain Specific Language,且都提供了静态的创建方法,我们可以使用import static简化书写。

重要概念

  • Identity当作业和触发器在Quartz调度程序中注册时,会获得标识键。JobKey和TriggerKey允许被置入group中,易于组织管理。唯一的,是name和group的组合标识。
  • JobDataMap是Map的实现,具有key-value相关操作,存储可序列化数据对象,供Job实例在执行时使用。可以使用usingJobData(key,value)在构建Jobdetail的时候传入数据,使用jobDetail.getJobDataMap()获取map。

Quartz设计理念:为什么设计Job和Trigger?

While developing Quartz, we decided that it made sense to create a separation between the schedule and the work to be performed on that schedule. This has (in our opinion) many benefits. For example, Jobs can be created and stored in the job scheduler independent of a trigger, and many triggers can be associated with the same job. Another benefit of this loose-coupling is the ability to configure jobs that remain in the scheduler after their associated triggers have expired, so that that it can be rescheduled later, without having to re-define it. It also allows you to modify or replace a trigger without having to re-define its associated job.

隔离schedule和schedule上执行的Job,优点是可见的:

可以独立于触发器创建作业并将其存储在作业调度程序中,并且许多触发器可以与同一作业相关联。这样的松耦合好处是什么?

  • 如果触发器过期,作业还可以保留在程序中,以便重新调度,而不必重新定义。
  • 如果你希望修改替换某个触发器,你不必重新定义其关联的作业。

最简单的Quartz使用案例

导入依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

简单案例如下

public class QuartzTest {
	// 你需要在start和shutdown之间执行你的任务。
    public static void main(String[] args) {

        try {
            // 从工厂中获取Scheduler示例
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            // 开始
            scheduler.start();

            // 定义Job,并将其绑定到HelloJob类中
            JobDetail job = JobBuilder.newJob(HelloJob.class)
                    .withIdentity("job1", "group1") // name 和 group
                    .usingJobData("username", "天乔巴夏") // 置入JobDataMap
                    .usingJobData("age", "20")
                    .withDescription("desc-demo")
                    .build();

            // 触发Job执行,每40s执行一次
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow() // 立即开始
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                            .withIntervalInSeconds(40)
                            .repeatForever())
                    .build();

            // 告诉 quartz 使用trigger来调度job
            scheduler.scheduleJob(job, trigger);
			// 关闭,线程终止
            scheduler.shutdown();

        } catch (SchedulerException se) {
            se.printStackTrace();
        }
    }

}

@Slf4j
@NoArgsConstructor
public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 从context中获取属性
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        JobKey key = jobDetail.getKey();
        Class<? extends Job> jobClass = jobDetail.getJobClass();
        String description = jobDetail.getDescription();

        String username = jobDataMap.getString("username");
        int age = jobDataMap.getIntValue("age");

        log.info("\nJobKey : {},\n JobClass : {},\n JobDesc : {},\n username : {},\n age : {}",
                key, jobClass.getName(), description, username, age);
    }
}

启动测试,打印日志如下:

01:23:12.406 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
01:23:12.414 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
01:23:12.430 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
01:23:12.430 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
01:23:12.432 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
01:23:12.433 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

01:23:12.433 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
01:23:12.433 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
01:23:12.434 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
01:23:12.434 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
01:23:12.443 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
01:23:12.445 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=com.hyhwky.HelloJob
01:23:12.451 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
01:23:12.452 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
01:23:12.452 [DefaultQuartzScheduler_Worker-1] INFO com.hyhwky.HelloJob - 
JobKey : group1.job1,
 JobClass : com.hyhwky.HelloJob,
 JobDesc : desc-demo,
 username : 天乔巴夏,
 age : 20

我们可以看到quartz已经被初始化了,初始化配置如下,在org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\quartz.properties

# 调度器配置
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false

# 线程池配置
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool 
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

# 存储配置
org.quartz.jobStore.misfireThreshold: 60000 #trigger 容忍时间60s

org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

更多的配置:Quartz Configuration Reference

Job实例和JobDetail

Job和JobDetail

  • Job是正在执行的作业实例,JobDetail是作业定义。
  • 一个Job可以创建多个JobDetail,拥有不同的JobDataMap。

这样定义有什么好处呢?举个例子吧,假设现在你定义了一个类实现了Job接口,比如:SendEmailJob。如果你希望根据用户的姓名,选择指定的人发送,那么你可以通过JobDataMap绑定参数传递进JobDetail中,也就是说我们需要创建两个不同的JobDetail,比如:SendEmailToSummerday和SendEmailToTQBX,他们拥有各自独立的JobDataMap,实现更加灵活。

Job的State和Concurrency

https://blog.csdn.net/fly_captain/article/details/83029440

@DisallowConcurrentExecution

该注解标注在Job类上,意思是不能并发从同一个JobDetail定义的多个实例,但可以同时执行多个不同的JobDetail定义的实例。

拿上面的例子继续举例,假设SendEmailJob标注了此注解,表明同一时间可以同时执行SendEmailToSummerday和SendEmailToTQBX,因为他们是不同的JobDetail,但是不能同时执行多个SendEmailToSummerday。

@PersistJobDataAfterExecution

该注解也标注在Job类上,告诉Scheduler正常执行完Job之后,重新存储更新一下JobDataMap。一般标注此注解的Job类应当考虑也加上@DisallowConcurrentExecution注解,以避免同时执行Job时出现JobDataMap存储的竞争。

Trigger常见使用

更多例子可以查看文档,非常详细:SimpleTrigger 和 CronTrigger

构建一个触发器,该触发器将立即触发,然后每五分钟重复一次,直到小时 22:00:

import static org.quartz.TriggerBuilder.*;
import static org.quartz.SimpleScheduleBuilder.*;
import static org.quartz.DateBuilder.*: 

 SimpleTrigger trigger = (SimpleTrigger) newTrigger()
    .withIdentity("trigger7", "group1")
    .withSchedule(simpleSchedule()
        .withIntervalInMinutes(5)
        .repeatForever())
    .endAt(dateOf(22, 0, 0))
    .build();

构建一个触发器,该触发器将在周三上午 10:42 触发,在系统默认值以外的时区中:

import static org.quartz.TriggerBuilder.*;
import static org.quartz.CronScheduleBuilder.*;
import static org.quartz.DateBuilder.*:

 trigger = newTrigger()
    .withIdentity("trigger3", "group1")
    .withSchedule(cronSchedule("0 42 10 ? * WED")) // [秒] [分] [时] [月的第几天] [月] [一星期的第几天] [年(可选)]
    .inTimeZone(TimeZone.getTimeZone("America/Los_Angeles"))
    .forJob(myJobKey)
    .build();

Quartz存储与持久化

Job的持久化是非常重要的,如果Job不能持久化,一旦不再有与之关联的Trigger,他就会自动从调度程序中被删除。

小结

Job存储器的类型:

具体使用方法:http://www.quartz-scheduler.org/documentation/quartz-2.2.2/tutorials/tutorial-lesson-09.html

以上就是要与大家分享的内容了

原文链接:https://www.cnblogs.com/summerday152/p/14192845.html

如果觉得本文对你有帮助,可以转发关注支持一下

相关推荐

十分钟让你学会LNMP架构负载均衡(impala负载均衡)

业务架构、应用架构、数据架构和技术架构一、几个基本概念1、pv值pv值(pageviews):页面的浏览量概念:一个网站的所有页面,在一天内,被浏览的总次数。(大型网站通常是上千万的级别)2、u...

AGV仓储机器人调度系统架构(agv物流机器人)

系统架构层次划分采用分层模块化设计,分为以下五层:1.1用户接口层功能:提供人机交互界面(Web/桌面端),支持任务下发、实时监控、数据可视化和报警管理。模块:任务管理面板:接收订单(如拣货、...

远程热部署在美团的落地实践(远程热点是什么意思)

Sonic是美团内部研发设计的一款用于热部署的IDEA插件,本文其实现原理及落地的一些技术细节。在阅读本文之前,建议大家先熟悉一下Spring源码、SpringMVC源码、SpringBoot...

springboot搭建xxl-job(分布式任务调度系统)

一、部署xxl-job服务端下载xxl-job源码:https://gitee.com/xuxueli0323/xxl-job二、导入项目、创建xxl_job数据库、修改配置文件为自己的数据库三、启动...

大模型:使用vLLM和Ray分布式部署推理应用

一、vLLM:面向大模型的高效推理框架1.核心特点专为推理优化:专注于大模型(如GPT-3、LLaMA)的高吞吐量、低延迟推理。关键技术:PagedAttention:类似操作系统内存分页管理,将K...

国产开源之光【分布式工作流调度系统】:DolphinScheduler

DolphinScheduler是一个开源的分布式工作流调度系统,旨在帮助用户以可靠、高效和可扩展的方式管理和调度大规模的数据处理工作流。它支持以图形化方式定义和管理工作流,提供了丰富的调度功能和监控...

简单可靠高效的分布式任务队列系统

#记录我的2024#大家好,又见面了,我是GitHub精选君!背景介绍在系统访问量逐渐增大,高并发、分布式系统成为了企业技术架构升级的必由之路。在这样的背景下,异步任务队列扮演着至关重要的角色,...

虚拟服务器之间如何分布式运行?(虚拟服务器部署)

  在云计算和虚拟化技术快速发展的今天,传统“单机单任务”的服务器架构早已难以满足现代业务对高并发、高可用、弹性伸缩和容错容灾的严苛要求。分布式系统应运而生,并成为支撑各类互联网平台、企业信息系统和A...

一文掌握 XXL-Job 的 6 大核心组件

XXL-Job是一个分布式任务调度平台,其核心组件主要包括以下部分,各组件相互协作实现高效的任务调度与管理:1.调度注册中心(RegistryCenter)作用:负责管理调度器(Schedule...

京东大佬问我,SpringBoot中如何做延迟队列?单机与分布式如何做?

京东大佬问我,SpringBoot中如何做延迟队列?单机如何做?分布式如何做呢?并给出案例与代码分析。嗯,用户问的是在SpringBoot中如何实现延迟队列,单机和分布式环境下分别怎么做。这个问题其实...

企业级项目组件选型(一)分布式任务调度平台

官网地址:https://www.xuxueli.com/xxl-job/能力介绍架构图安全性为提升系统安全性,调度中心和执行器进行安全性校验,双方AccessToken匹配才允许通讯;调度中心和执...

python多进程的分布式任务调度应用场景及示例

多进程的分布式任务调度可以应用于以下场景:分布式爬虫:importmultiprocessingimportrequestsdefcrawl(url):response=re...

SpringBoot整合ElasticJob实现分布式任务调度

介绍ElasticJob是面向互联网生态和海量任务的分布式调度解决方案,由两个相互独立的子项目ElasticJob-Lite和ElasticJob-Cloud组成。它通过弹性调度、资源管控、...

分布式可视化 DAG 任务调度系统 Taier 的整体流程分析

Taier作为袋鼠云的开源项目之一,是一个分布式可视化的DAG任务调度系统。旨在降低ETL开发成本,提高大数据平台稳定性,让大数据开发人员可以在Taier直接进行业务逻辑的开发,而不用关...

SpringBoot任务调度:@Scheduled与TaskExecutor全面解析

一、任务调度基础概念1.1什么是任务调度任务调度是指按照预定的时间计划或特定条件自动执行任务的过程。在现代应用开发中,任务调度扮演着至关重要的角色,它使得开发者能够自动化处理周期性任务、定时任务和异...

取消回复欢迎 发表评论: