「这是我参与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基础上开发的,换别的解决方案,学习成本也比较大。这就需要大家根据自己的具体应用情况来抉择了。好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊
\