SpringBoot结合Quartz开发定时任务(四)

300 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

1、前言

上一篇的分享中,我为大家分享了在微服务项目中基于Quartz开发定时任务的改造。但是,对于分布式环境的支持不太好。对于一个任务,不同的实例是否需要都执行,执行意外中断了怎么办?任务的分片交替执行等问题都考虑到。其实,Quartz本身也是支持分布式环境开发的。那么本篇为大家介绍下具体应用。

2、分布式定时任务的应用(Quartz)

 //初试化定时任务  
public class QuartzJobConfig { 
​
    @PostConstruct
    public void quartzJobInit() throws Exception {
        logger.info("开始初始化定时任务");
        schedulerListenerComponent.reStartAllSchedulerListeners();
        triggerListenerComponent.reStartAllTriggerListeners();
        jobListenerComponent.reStartAllJobListeners();
        reStartAllJobs();
        logger.info("初始化定时任务结束");
    }
​
    private void reStartAllJobs() throws SchedulerException {
        //只允许一个线程进入操作
        synchronized (logger) {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            Set<JobKey> set = scheduler.getJobKeys(GroupMatcher.anyGroup());
            //暂停所有JOB
            scheduler.pauseJobs(GroupMatcher.anyGroup());
            //删除从数据库中注册的所有JOB
            for (JobKey jobKey : set) {
                scheduler.unscheduleJob(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup()));
                scheduler.deleteJob(jobKey);
            }
            //从数据库中注册的所有JOB
            List<QuartzInfo> quartzInfos = quartzDao.queryInitQueries();
            for(QuartzInfo job : quartzInfos){
                logger.info("Job register name : {} , group : {} , cron : {}", job.getJobName(), job.getJobGroup(), job.getCronExpression());
                JobDataMap map = job.getJobDataMap();
                JobKey jobKey = QuartzUtil.getJobKey(job);
                JobDetail jobDetail = QuartzUtil.getJobDetail(jobKey, job.getDescription(), map, job.getJobClassPath()); 
                if (job.getStatus().equals("OPEN")) {
                    scheduler.scheduleJob(jobDetail, QuartzUtil.getCornTrigger(TriggerKey.triggerKey(job.getJobName(), job.getJobGroup())
                            , job.getDescription(), map, job.getCronExpression(), jobKey));
                } else {
                    logger.info("Job jump name : {} , Because {} status is {}", job.getJobName(), job.getJobName(), job.getStatus());
                }
            }
        }
    }
​
}
​
//任务监听器组件
@Component
public class JobListenerComponent { 
​
    //重启所有任务监听
    public void reStartAllJobListeners() throws SchedulerException {
        logger.info("根据配置重启任务监听——————————————开始");
        //根据配置重启所有调度器监听
        List<JobListenerInfo> jobListenerInfos = quartzDao.queryJobListeners();
        for(JobListenerInfo jLI : jobListenerInfos){
            logger.info("开始创建任务监听{}", jLI);
            JobListener jobListener = (JobListener)Class.forName(jLI.getClassPath()).newInstance();
            removeJobListener(jLI.getName());
            switch (jLI.getJobListenerType()){
                case ListenerType.ONE:
                    createJobListener(jobListener, JobKey.jobKey(jLI.getJobName(), jLI.getJobGroup()));
                    break;
                case ListenerType.GROUP:
                    createGroupJobListener(jobListener, jLI.getJobGroup());
                    break;
                case ListenerType.ALL:
                    createAllJobListener(jobListener);
                    break;
                default:
                    logger.error("暂不支持的触发器监听类型{}", jLI.getJobListenerType());
            }
        }
        logger.info("根据配置重启任务监听——————————————结束");
    }
​
    //创建任务监听(监听某个特殊任务)
    public void createJobListener(JobListener jobListener, JobKey jobKey) throws SchedulerException {
        scheduler.getListenerManager().addJobListener(jobListener, KeyMatcher.keyEquals(jobKey));
    }
​
    //创建任务监听(监听一组Job) 
    public void createGroupJobListener(JobListener jobListener, String groupName) throws SchedulerException {
        scheduler.getListenerManager().addJobListener(jobListener, GroupMatcher.jobGroupEquals(groupName));
    }
​
    //创建任务监听(监听所有的Job)
    public void createAllJobListener(JobListener jobListener) throws SchedulerException {
        scheduler.getListenerManager().addJobListener(jobListener, EverythingMatcher.allJobs());
    }
​
    //移除任务监听
    public void removeJobListener(String name) throws SchedulerException {
        scheduler.getListenerManager().removeJobListener(name);
    }
​
}

这里Quartz是通过数据库悲观锁的来实现同一个任务只有一个节点在执行,保证了高可用,但造成了一定程度上的资源浪费,但这个项目是应用在金融行业,对高可用的要求远远大于高并发,而且原有的也是在Quartz基础上开发的,换别的解决方案,学习成本也比较大。这就需要大家根据自己的具体应用情况来抉择了。好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊

\