基于quartz的分布式调度实现

一、简介

Quartz是一个完全由java编写的开源作业调度框架,适用用多种环境:单节点以及集群环境。集群环境下具有伸缩性、高可用性、负载均衡等特性。本章将主要介绍在集群环境下分布式部署的实现。

二、pom引入

基于springboot项目

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

三、配置

job的存储依赖于mysql

# 链接的mysql配置quartz会将job信息等存储到自己生成的表中
spring.datasource.url=jdbc:mysql://localhost:3306/database_name?characterEncoding=utf8&serverTimezone=UTC
# quzrtz configuration
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema = always
spring.quartz.overwrite-existing-jobs=true
spring.quartz.properties.org.quartz.scheduler.instanceName = MyClusteredScheduler
spring.quartz.properties.org.quartz.scheduler.instanceId = AUTO

spring.quartz.properties.org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount = 50
spring.quartz.properties.org.quartz.threadPool.threadPriority = 5
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread= true
# Configure the jobStore
spring.quartz.properties.org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.useProperties=false
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=20000

四、实现

quartz框架主要核心组件包括调度器(scheduler)、触发器(Trigger)、作业(Job)。

  • 调度器:作为作业的总指挥,做为定时任务容器,是quartz最上层的东西,它提携了所有触发器和作业,使它们协调工作,每个Scheduler都存有JobDetail和Trigger的注册,一个Scheduler中可以注册多个JobDetail和多个Trigger。
  • 触发器:作为作业的操作者,Trigger做为作业的定时管理工具,一个Trigger只能对应一个作业实例,而一个作业实例可对应多个触发器。
  • 作业为应用的功能模块,负责处理应用的业务逻辑。
4.1.JobManager

负责启动调度并绑定job和Tigger进行绑定,并执行任务的增删改查。

@Slf4j
@Component
public class TaskJobManager {
    @Resource
    private Scheduler schedulerQuartz;
	// job可以按照类别放入不同的组已形成一定的隔离
    private final static String TRIGGER_GROUP = "组名";

    public void addCronJob(String jobName, JobDataModel jobData, String cron) {
        try{
            // 启动调度器
            if (!schedulerQuartz.isStarted()) {
                schedulerQuartz.start();
            }
            deleteJob(jobName);
            addJob(jobName, jobData, cron);
        } catch (SchedulerException e) {
            log.error("addCronJob失败", e);
            throw new GException(ErrorMessage.QUARTZ_SCHEDULER_EXCEPTION, "addCronJob失败");
        }
    }

    private void addJob(String jobName, JobDataModel jobData, String cron) {
        try {
            log.info("构建新的Job, JobData:{}, Cron:{}", JSON.toJSONString(jobData), cron);
            //构建job信息,不通的触发去可以与不通的job绑定
            JobDetail jobDetail = JobBuilder.newJob(Job1.class)
                    .withIdentity(jobName, TRIGGER_GROUP)
                    .storeDurably()//即使没有Trigger关联时,也不需要删除该JobDetail
                    .build();
            jobDetail.getJobDataMap().put(Cons.JOB_DATA, jobData);
            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .forJob(jobDetail)//关联上述的JobDetail
                    .withIdentity(jobName, TRIGGER_GROUP)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))// "0/1 * * * * ?"
                    .build();
            schedulerQuartz.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            log.error("创建定时任务失败", e);
            throw new Exception("创建定时任务失败");
        }
    }


    public void updateJob(String jobName, JobDataModel jobDataModel, String cron) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            CronTrigger trigger = (CronTrigger) schedulerQuartz.getTrigger(triggerKey);
            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            //参数修改
            JobKey jobKey = JobKey.jobKey(jobName, TRIGGER_GROUP);
            JobDataModel jobDataMap = (JobDataModel) schedulerQuartz.getJobDetail(jobKey).getJobDataMap().get(Cons.JOB_DATA);
            jobDataMap.setEtlTaskSch(jobDataModel.getEtlTaskSch());
            jobDataMap.setCallFailRetryTimes(jobDataMap.getCallFailRetryTimes());
            // 按新的trigger重新设置job执行
            schedulerQuartz.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            log.error("更新定时任务失败" + e);
            throw new Exception("更新定时任务失败");
        }
    }

    public void deleteJob(String jobName) {
        try {
            val triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP);
            schedulerQuartz.pauseTrigger(triggerKey);
            if (schedulerQuartz.checkExists(triggerKey)) {
                schedulerQuartz.unscheduleJob(TriggerKey.triggerKey(jobName, TRIGGER_GROUP));
            }
            val jobKey = JobKey.jobKey(jobName, TRIGGER_GROUP);
            if (schedulerQuartz.checkExists(jobKey)) {
                schedulerQuartz.deleteJob(jobKey);
            }
        } catch (SchedulerException e) {
            log.error("更新定时任务失败" + e);
            throw new Exception("删除定时任务失败");
        }
    }
}
4.2. Job

在调度器调起始时job会被触发器触发从而执行具体的job业务逻辑。

public class Job1 QuartzJobBean {
    @Override
    protected void executeInternal(@NonNull JobExecutionContext jobExecutionContext) {
    	// 获取job中的jobDataMap--构建job中某些数据可以存储到jobDataDetail中
        val jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        val jobDataModel = (JobDataModel) jobDataMap.get(Cons.JOB_DATA);
        try {
             // 在此执行具体的业务
        } catch (OtherServiceException e) {
            log.error("任务执行异常, errorMessage:{}", e.getMsg());
        }
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。 Quartz的优势: 1、Quartz是一个任务调度框架(库),它几乎可以集成到任何应用系统中。 2、Quartz是非常灵活的,它让您能够以最“自然”的方式来编写您的项目的代码,实现您所期望的行为 3、Quartz是非常轻量级的,只需要非常少的配置 —— 它实际上可以被跳出框架来使用,如果你的需求是一些相对基本的简单的需求的话。 4、Quartz具有容错机制,并且可以在重启服务的时候持久化(”记忆”)你的定时任务,你的任务也不会丢失。 5、可以通过Quartz,封装成自己的分布式任务调度实现强大的功能,成为自己的产品。6、有很多的互联网公司也都在使用Quartz。比如美团 Spring是一个很优秀的框架,它无缝的集成了Quartz,简单方便的让企业级应用更好的使用Quartz进行任务的调度。   课程说明:在我们的日常开发中,各种大型系统的开发少不了任务调度,简单的单机任务调度已经满足不了我们的系统需求,复杂的任务会让程序猿头疼, 所以急需一套专门的框架帮助我们去管理定时任务,并且可以在多台机器去执行我们的任务,还要可以管理我们的分布式定时任务。本课程从Quartz框架讲起,由浅到深,从使用到结构分析,再到源码分析,深入解析Quartz、Spring+Quartz,并且会讲解相关原理, 让大家充分的理解这个框架和框架的设计思想。由于互联网的复杂性,为了满足我们特定的需求,需要对Spring+Quartz进行二次开发,整个二次开发过程都会进行讲解。Spring被用在了越来越多的项目中, Quartz也被公认为是比较好用的定时器设置工具,学完这个课程后,不仅仅可以熟练掌握分布式定时任务,还可以深入理解大型框架的设计思想。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值