前一节分析了一下elastic的启动过程,接下来看一下它的调度过程。elastic-job的调度引擎是基于quartz,也就是说调度这一块都是quartz来负责,elastic-job则在上层逻辑进行处理。
那么从作业开始调度开始看起
public void init() {
// 1.将配置更新到注册中心
LiteJobConfiguration liteJobConfigFromRegCenter = schedulerFacade.updateJobConfiguration(liteJobConfig);
// 2.缓存当前作业分片数到本地
JobRegistry.getInstance().setCurrentShardingTotalCount(liteJobConfigFromRegCenter.getJobName(), liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getShardingTotalCount());
// 3.JobScheduleController 实例,controller类负责控制quartz调度引擎
JobScheduleController jobScheduleController = new JobScheduleController(
createScheduler(), createJobDetail(liteJobConfigFromRegCenter.getTypeConfig().getJobClass()), liteJobConfigFromRegCenter.getJobName());
// 4.缓存作业对应的controller对应的
JobRegistry.getInstance().registerJob(liteJobConfigFromRegCenter.getJobName(), jobScheduleController, regCenter);
// 5.作业开始调度前,更改一些配置()
schedulerFacade.registerStartUpInfo(!liteJobConfigFromRegCenter.isDisabled());
// 6.根据cron表达式开始调度作业
jobScheduleController.scheduleJob(liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getCron());
}
前几个步前面都说过,主要看第六步,第六步是调用JobSchedulerController控制器来根据cron表达式来使用quartz来开启调度。
public void scheduleJob(final String cron) {
try {
if (!scheduler.checkExists(jobDetail.getKey())) {
scheduler.scheduleJob(jobDetail, createTrigger(cron));
}
scheduler.start();
} catch (final SchedulerException ex) {
throw new JobSystemException(ex);
}
}
先检查了schdeduler是否设置了jobDetail,如果没有则设置jobDetail,最后调用start开启任务调度。
在实例化JobSchedulerController时,创建JobDetail,使用的jobClass是LiteJob
private JobDetail createJobDetail(final String jobClass) {
// 使用LiteJob类作为中间类,协调elastic和quartz
JobDetail result = JobBuilder.newJob(LiteJob.class).withIdentity(liteJobConfig.getJobName()).build();
// 作业门面设置到jobDataMap最终设置到LiteJob中
result.getJobDataMap().put(JOB_FACADE_DATA_MAP_KEY, jobFacade);
Optional<ElasticJob> elasticJobInstance = createElasticJobInstance();
if (elasticJobInstance.isPresent()) {
// 设置真实的作业执行类到LiteJob
result.getJobDataMap().put(ELASTIC_JOB_DATA_MAP_KEY, elasticJobInstance.get());
} else if (!jobClass.equals(ScriptJob.class.getCanonicalName())) {
try {
result.getJobDataMap().put(ELASTIC_JOB_DATA_MAP_KEY, Class.forName(jobClass).newInstance());
} catch (final ReflectiveOperationException ex) {
throw new JobConfigurationException("Elastic-Job: Job class '%s' can not initialize.", jobClass);
}
}
return result;
}
LiteJob是一个中间类,用于衔接quartz和elastic-job,具体如何操作的看下LiteJob
public final class LiteJob implements Job {
// 提供set方法,可以从JobDataMap取相同key的value自动设置到属性上
@Setter
private ElasticJob elasticJob;
@Setter
private JobFacade jobFacade;
@Override
public void execute(final JobExecutionContext context) throws JobExecutionException {
// 根据job类型获取具体的job执行器
JobExecutorFactory.getJobExecutor(elasticJob, jobFacade).execute();
}
}
这个类有两个属性,一个是elastic-job的作业接口,后面所有类型的作业都是实现了这个接口,第二个是作业的门面接口,包括了一些作业执行状态更改配置加载的一些用途。这里有个小技巧,对相应的属性提供set方法,然后就可以将创建jobDetail时设置到JobDataMap里面的数据自动注入了,但是key的名字一定要和属性名一致。当作业触发执行时,根据job类型获取Executor进行执行,最终调用真实作业的execute方法。
public static AbstractElasticJobExecutor getJobExecutor(final ElasticJob elasticJob, final JobFacade jobFacade) {
if (null == elasticJob) {
return new ScriptJobExecutor(jobFacade);
}
if (elasticJob instanceof SimpleJob) {
return new SimpleJobExecutor((SimpleJob) elasticJob, jobFacade);
}
if (elasticJob instanceof DataflowJob) {
return new DataflowJobExecutor((DataflowJob) elasticJob, jobFacade);
}
throw new JobConfigurationException("Cannot support job type '%s'", elasticJob.getClass().getCanonicalName());
}
本文主讲SimpleJob类型作业,其他自行探讨。我们再进入SimpleJobExecutor查看
public final class SimpleJobExecutor extends AbstractElasticJobExecutor {
private final SimpleJob simpleJob;
public SimpleJobExecutor(final SimpleJob simpleJob, final JobFacade jobFacade) {
super(jobFacade);
this.simpleJob = simpleJob;
}
// 调用真实的作业执行
@Override
protected void process(final ShardingContext shardingContext) {
simpleJob.execute(shardingContext);
}
}
好像发现并没有execute方法哎,别急,先看下process方法,该方法直接调用了真实的作业类型。而对于execute则是由其父类抽象实现具体如下图
最终还是调用了Executor,而在executor中调用了真实作业的execute方法,并将分片参数传入。至于分片相关后面章节会提到。