elastic-job源码分析(一)启动过程

elastic-job版本 2.1.5,由于master分支使用的式curator5.x,支持zookeeper需要3.6.x,对3.5和3.4支持不是好,所以采用了较低版本的elastic-job源码进行解析

elastic-job启动分析:

elastic-job配置的一个核心类JobScheduler(本文只讲述SimpleJob类型作业), 直接看该类的init方法

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());
 }

Elastic-job启动主要看init方法,第一步将本地的作业配置持久化到注册中心具体如下(configService.persist):

public void persist(final LiteJobConfiguration liteJobConfig) {
        // 检测作业实现类名是否一致
        checkConflictJob(liteJobConfig);
        // 判断当前是否存在config节点,不存在则写入,存在则查看是否允许覆盖当前配置
        if (!jobNodeStorage.isJobNodeExisted(ConfigurationNode.ROOT) || liteJobConfig.isOverwrite()) {
            jobNodeStorage.replaceJobNode(ConfigurationNode.ROOT, LiteJobConfigurationGsonFactory.toJson(liteJobConfig));
        }
    }

第二步缓存当前分片到本地,便于后期配置节点更改时进行对比,判断是否需要重新分片。JobRegistry实例采用的是单例模式,也就是说当前server下面的所有作业都会注册到同一个JobRegistry,具体如下:

// jobName对应controller,同时controller里面保存了一个quartz实例
    private Map<String, JobScheduleController> schedulerMap = new ConcurrentHashMap<>();
    // jobName对应注册中心
    private Map<String, CoordinatorRegistryCenter> regCenterMap = new ConcurrentHashMap<>();
    // jobName对应作业实例,主要作用就是获取当前server ip和 实例id,instanceId采用的是ip + 分割符 + 进程id,这样可以避免
    // 保证同一节点可以存在不同的应用服务
    private Map<String, JobInstance> jobInstanceMap = new ConcurrentHashMap<>();
    // 保存作业运行信息
    private Map<String, Boolean> jobRunningMap = new ConcurrentHashMap<>();
    //  jobName对应的分片数
    private Map<String, Integer> currentShardingTotalCountMap = new ConcurrentHashMap<>();

第三步实例话作业控制器,主要用来控制quartz调度引擎,包括控制调度,暂停,恢复,已经停止。具体属性如下:

	// quartz的调度器
     private final Scheduler scheduler;
    // quartz的jobDetail
    private final JobDetail jobDetail;
    
    private final String triggerIdentity;

这里有点要注意的是创建detail时有一个细节,这也是elastic使用quartz时的桥梁

private JobDetail createJobDetail(final String jobClass) {
        JobDetail result = JobBuilder.newJob(LiteJob.class).withIdentity(liteJobConfig.getJobName()).build();
        result.getJobDataMap().put(JOB_FACADE_DATA_MAP_KEY, jobFacade);
        Optional<ElasticJob> elasticJobInstance = createElasticJobInstance();
        if (elasticJobInstance.isPresent()) {
            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;
    }

这里使用的job类型是LiteJob,这个类很重,它是quartz调度时会转接到你写的任务类上。

public final class LiteJob implements Job {
    
    // 提供set方法,可以从JobDataMap中自动设置到属性上
    @Setter
    private ElasticJob elasticJob;
    @Setter
    private JobFacade jobFacade;
    @Override
    public void execute(final JobExecutionContext context) throws JobExecutionException {
        JobExecutorFactory.getJobExecutor(elasticJob, jobFacade).execute();
    }
}

在quartz执行作业时,会执行我们真正的作业。
第四步就是简单的缓存作业的控制器,一个作业对应一个quartz的scheduler
第五步则是在调度作业前进行一些设置,比如注册中心的监听,leader选举,server状态更新,instace实例持久化到注册中心(临时节点,一旦断开连接就会消失),设置分片标记,初始化作业监听等

public void registerStartUpInfo(final boolean enabled) {
        // 注册中心节点监听
        listenerManager.startAllListeners();
        // 选举leader(负责处理分片)
        leaderService.electLeader();
        // 更新server状态
        serverService.persistOnline(enabled);
        // 作业实例上线
        instanceService.persistOnline();
        // 作业分片标记设置
        shardingService.setReshardingFlag();
        // 初始化作业监听器
        monitorService.listen();
        // 开始调节分布式作业不一致问题
        if (!reconcileService.isRunning()) {
            reconcileService.startAsync();
        }
    }

以上具体细节后面节选再说,第六步开始调度作业,也就是正式的开始调度了,前面的都算是一个铺垫,调度时通过控制器直接调用quartz的scheduler的start方法开始调度作业。

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);
        }
    }

以上是elastic-job的启动过程,下一节会说一下节点监听的具体作用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三寸花笺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值