我们开发经常使用到Quartz框架,下面我就从Quartz特点、原理、使用等来详解Quartz框架@mikechen
Quartz简介
Quartz是一个开源的任务调度框架,用于在Java应用程序中实现作业调度,它提供了灵活且功能强大的调度功能,来执行定时任务。
Quartz特点
Quartz特点如下:
- 方便:完全由Java写成,方便集成(Spring);
- 灵活的任务调度:Quartz提供了灵活的任务调度功能,可以按照指定的时间表执行任务,也可以根据一定的规则进行重复执行。
- 它支持多种类型的触发器,如简单触发器、Cron触发器和日历触发器,可以满足各种调度需求。
- 可靠性和持久性:Quartz支持作业和触发器的持久化,可以将它们保存在数据库中。
- 分布式和集群支持:Quartz框架支持分布式和集群模式,可以将多个调度器连接在一起,共享作业和触发器。
Quartz使用场景
典型的使用场景主要用来执行定时任务,例如:
- 定时发送信息;
- 定时生成报表;
- 自动更新静态数据;
- 自动结账等等;
Quartz核心概念
1.作业(Job)和触发器(Trigger)
Quartz的核心概念是作业和触发器,作业是需要执行的任务,而触发器定义了作业何时执行的规则。
2.调度器(Scheduler)
调度器是Quartz的中心组件,负责管理作业和触发器的注册和执行,调度器可以启动、暂停、停止作业的执行,并且负责将作业分配给合适的执行线程。
3.作业执行器(Job Executor)
作业执行器负责实际执行作业的代码逻辑,提供了多种作业执行器的实现,包括简单的Java类作业执行器、无状态作业执行器和可集群的作业执行器等。
4.触发器类型
Quartz支持多种类型的触发器,包括:
- 简单触发器(SimpleTrigger):简单触发器允许在指定的时间间隔内重复执行作业;
- Cron触发器(CronTrigger):允许使用Cron表达式定义更复杂的执行规则;
- 日历触发器(CalendarTrigger):可以排除指定的日期或时间段,控制作业的执行;
5.监听器(Listener)
Quartz提供了监听器机制,可以通过监听器在作业执行前后或触发器触发时执行自定义的逻辑。监听器可以用于记录日志、发送通知或执行其他特定的任务。
6.持久化
Quartz框架支持作业和触发器的持久化,可以将它们保存在数据库中,以便在应用程序重启后重新加载,这样可以确保作业的持久性和可靠性。
7.集群支持
Quartz提供了集群支持,可以将多个调度器连接在一起,共享作业和触发器。
集群模式下,作业只会在一个调度器节点上执行,其他节点将处于待命状态,如果当前执行作业的节点发生故障,Quartz会自动将作业转移给其他可用的节点。
Quartz核心架构
Quartz框架主要核心组件包括:
1.Scheduler任务调度
调度器是Quartz的核心组件,负责管理作业和触发器的注册和执行。
它负责调度作业的执行,根据触发器的定义确定作业的执行时间,并将作业分配给合适的执行线程。
调度器可以启动、暂停和停止作业的执行,还可以管理调度器的配置和状态。
2.Job任务
作业是需要执行的任务,可以通过实现org.quartz.Job
接口或扩展org.quartz.Job
类来定义作业。
其实Job是接口,其中只有一个execute方法,我们只需要 implements 此接口,重写 execute(*) 方法。
3.Trigger触发器
Quartz提供了多种类型的触发器,如简单触发器(SimpleTrigger)、Cron触发器(CronTrigger)和日历触发器(CalendarTrigger)。
触发器可以指定作业的执行时间、重复间隔、执行次数等参数。
执行任务的规则;比如每天,每小时等。
4.作业执行器(Job Executor)
作业执行器负责实际执行作业的代码逻辑,Quartz提供了多种作业执行器的实现,包括简单的Java类作业执行器、无状态作业执行器和可集群的作业执行器等。
作业执行器接收到调度器分配的作业后,负责调用作业的执行方法。
4.JobDetail任务细节
任务细节,Quartz执行Job时,需要新建个Job实例,但是不能直接操作Job类,所以通过JobDetail来获取Job的名称、描述信息。
调度器作为作业的总指挥,触发器作为作业的操作者,作业为应用的功能模块。
5.监听器(Listener)
Quartz框架提供了监听器机制,可以通过监听器在作业执行前后或触发器触发时执行自定义的逻辑。
可以实现org.quartz.listeners.JobListener
接口或org.quartz.listeners.TriggerListener
接口,并将监听器注册到调度器中,以便在作业和触发器事件发生时触发监听器的回调方法。
Quartz集群部署实践
Quartz与Spring结合使用,Spring通过提供org.springframework.scheduling.quartz下的封装类对Quartz支持。
1.Quartz集群部署
Quartz集群中的每个节点是一个独立的Quartz应用,它又管理着其他的节点。
该集群需要分别对每个节点分别启动或停止,不像应用服务器的集群,独立的Quartz节点并不与另一个节点或是管理节点通信。
Quartz应用是通过数据库表来感知到另一应用。只有使用持久的JobStore才能完成Quqrtz集群。
基于Spring的集群配置:
<!-- 调度工厂 --> <bean id=" quartz Scheduler" class="org.springframework.scheduling. quartz .SchedulerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name=" quartz Properties"> <props> <prop key="org. quartz .scheduler.instanceName">CRMscheduler</prop> <prop key="org.quartz.scheduler.instanceId">AUTO</prop> <!-- 线程池配置 --> <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop> <prop key="org.quartz.threadPool.threadCount">20</prop> <prop key="org.quartz.threadPool.threadPriority">5</prop> <!-- JobStore 配置 --> <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop> <!-- 集群配置 --> <prop key="org.quartz.jobStore.isClustered">true</prop> <prop key="org.quartz.jobStore.clusterCheckinInterval">15000</prop> <prop key="org.quartz.jobStore.maxMisfiresToHandleAtATime">1</prop> <prop key="org.quartz.jobStore.misfireThreshold">120000</prop> <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop> </props> </property> <property name="schedulerName" value="CRMscheduler" /> <!--必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 --> <property name="startupDelay" value="30" /> <property name="applicationContextSchedulerContextKey" value="applicationContextKey" /> <!--可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 --> <property name="overwriteExistingJobs" value="true" /> <!-- 设置自动启动 --> <property name="autoStartup" value="true" /> <!-- 注册触发器 --> <property name="triggers"> <list> <ref bean="userSyncScannerTrigger" /> ...... </list> </property> <!-- 注册jobDetail --> <property name="jobDetails"> <list> </list> </property> <property name="schedulerListeners"> <list> <ref bean="quartzExceptionSchedulerListener" /> </list> </property> </bean>
2.下面是Quartz集群部署的步骤:
1)创建数据库表
首先,需要创建一个用于存储作业和触发器信息的数据库表。
Quartz提供了多种数据库存储的实现,您可以选择适合您的数据库类型,并按照Quartz提供的脚本或文档创建相应的表结构。
2)配置调度器实例
在每个调度器实例上,需要配置Quartz调度器的相关属性,这些属性包括数据库连接信息、作业执行线程数、线程池配置等。
3)配置数据源和数据存储
在集群环境中,每个调度器实例需要共享同一个数据库存储,需要配置相同的数据源(DataSource)信息,并使用相同的表前缀(Table Prefix)来区分不同的调度器实例。
4)配置调度器绑定
在每个调度器实例上,您需要配置调度器的绑定(Scheduler Binding)。
绑定是为了确保每个调度器实例都能够通过相同的调度器名称和实例ID连接到同一个调度器集群。
可以通过配置org.quartz.scheduler.instanceId
和org.quartz.scheduler.instanceName
属性来实现。
5)配置网络通信
确保集群中的每个调度器实例可以互相通信,可以使用标准的网络通信协议,如TCP/IP或UDP,来实现调度器之间的通信。
6)启动调度器实例
在每个调度器实例上启动Quartz调度器,调度器实例会尝试连接到集群中的其他调度器实例,并进行通信和协调。
7)验证集群配置
可以通过查看日志、监控调度器状态或观察作业执行情况来确认集群部署的正常运行,确保作业在集群中的不同实例上均衡执行,并能够在主实例故障时自动切换到其他可用实例。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》