xxl-job源码解析
从别人那边拷贝的原理图
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210717223647929.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxNTg3Nzk1,size_16,color_FFFFFF,t_70)
公司版本的xxl-job,东拼西凑的版本
与V2.0.0 这个版本相似
https://www.xuxueli.com/xxl-job/#7.11%20版本%20V1.5.2%20特性[2017-02-28]
代码地址
https://gitee.com/xuxueli0323/xxl-job.git
调度中心
@Bean(initMethod = "start", destroyMethod = "destroy")
public JobDynamicScheduler getXxlJobDynamicScheduler(SchedulerFactoryBean schedulerFactory){
Scheduler scheduler = schedulerFactory.getScheduler();
JobDynamicScheduler xxlJobDynamicScheduler = new JobDynamicScheduler();
xxlJobDynamicScheduler.setScheduler(scheduler);
return xxlJobDynamicScheduler;
}
启动
public void start() throws Exception {
// valid
Assert.notNull(scheduler, "quartz scheduler is null");
// init i18n
initI18n();
//job注册线程
JobRegistryMonitorHelper.getInstance().start();
//job失败线程
JobFailMonitorHelper.getInstance().start();
//调度中心rpc客户端
initRpcProvider();
logger.info(">>>>>>>>> init dbaas-job admin success.");
}
运行中
JobRegistryMonitorHelper
一直保持执行器信息的更新,只更新自动注册的执行器,把表h_qrtz_trigger_registry的数据更新到h_qrtz_trigger_group,默认90秒更新一次
public void start(){
registryThread = new Thread(new Runnable() {
@Override
public void run() {
while (!toStop) {
try {
// auto registry group
List<JobGroup> groupList = JobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
if (CollectionUtils.isNotEmpty(groupList)) {
// remove dead address (admin/executor)
JobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(RegistryConfig.DEAD_TIMEOUT);
// fresh online address (admin/executor)
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
List<JobRegistry> list = JobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT);
if (list != null) {
for (JobRegistry item: list) {
if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
String appName = item.getRegistryKey();
List<String> registryList = appAddressMap.get(appName);
if (registryList == null) {
registryList = new ArrayList<String>();
}
if (!registryList.contains(item.getRegistryValue())) {
registryList.add(item.getRegistryValue());
}
appAddressMap.put(appName, registryList);
}
}
}
// fresh group address
for (JobGroup group: groupList) {
List<String> registryList = appAddressMap.get(group.getAppName());
String addressListStr = null;
if (CollectionUtils.isNotEmpty(registryList)) {
Collections.sort(registryList);
addressListStr = StringUtils.join(registryList, ",");
}
group.setAddressList(addressListStr);
JobAdminConfig.getAdminConfig().getXxlJobGroupDao().updateJobGroup(group);
}
}
} catch (Exception e) {
logger.error("job registry instance error:{}", e);
}
try {
TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
} catch (InterruptedException e) {
logger.error("job registry instance error:{}", e);
}
}
}
});
registryThread.setDaemon(true);
registryThread.start();
}
JobTriggerPoolHelper
任务触发线程池
private ThreadPoolExecutor triggerPool = new ThreadPoolExecutor(
32,
256,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(1000));
public void addTrigger(final int jobId, final TriggerTypeEnum triggerType, final int failRetryCount, final String executorShardingParam, final String executorParam) {
triggerPool.execute(new Runnable() {
@Override
public void run() {
JobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam);
}
});
}
定时任务触发
从启动接口开始
JobServiceImplJobServiceImpl
@Override
public JobWrapper<String> start(int id) {
JobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
String group = String.valueOf(xxlJobInfo.getJobGroup());
String name = String.valueOf(xxlJobInfo.getId());
String cronExpression = xxlJobInfo.getJobCron();
try {
boolean ret = JobDynamicScheduler.addJob(name, group, cronExpression);
return ret ? JobWrapper.SUCCESS : JobWrapper.FAIL;
} catch (SchedulerException e) {
logger.error(e.getMessage(), e);
return JobWrapper.FAIL;
}
}
JobDynamicScheduler
把定时任务注册到quartz中
public static boolean addJob(String jobName, String jobGroup, String cronExpression) throws SchedulerException {
// 1、job key
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
JobKey jobKey = new JobKey(jobName, jobGroup);
// 2、valid
if (scheduler.checkExists(triggerKey)) {
return true; // PASS
}
// 3、corn trigger
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
// 4、job detail
Class<? extends Job> jobClass_ = RemoteHttpJobBean.class; // Class.forName(jobInfo.getJobClass());
JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
/*if (jobInfo.getJobData()!=null) {
JobDataMap jobDataMap = jobDetail.getJobDataMap();
jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));
// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
}*/
// 5、schedule job
Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
logger.info(">>>>>>>>>>> addJob success, jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
return true;
}
RemoteHttpJobBean
quartz 定时任务和手动任务触发的调用方法一致
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
// load jobId
JobKey jobKey = context.getTrigger().getJobKey();
Integer jobId = Integer.valueOf(jobKey.getName());
// trigger
JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null);
}
手动触发任务
从触发接口开始
JobServiceImpl
@Override
public JobWrapper<String> triggerJob(int id, Map<String, String> params) {
String executorParam = "";
if (params != null) {
executorParam = params.get("executorParam");
// force cover job param
if (executorParam == null) {
executorParam = "";
}
} else {
executorParam = "";
}
JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam);
return JobWrapper.SUCCESS;
}
JobTrigger
public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam) {
// load data
JobInfo jobInfo = JobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId);
if (jobInfo == null) {
logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId);
return;
}
Date curTime = new Date();
//必须时间相同才能触发
if(jobInfo.getBeginTime() != null && curTime.getTime() < jobInfo.getBeginTime().getTime()) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
logger.warn(">>>>>>>>>>>> trigger fail, trigger time invalid,jobId={},curTime={},beginTime={}", jobId,df.format(curTime),df.format(jobInfo.getBeginTime()));
return;
}
if(jobInfo.getEndTime() != null && curTime.getTime() > jobInfo.getEndTime().getTime()) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
logger.warn(">>>>>>>>>>>> trigger fail, trigger time invalid,jobId={},curTime={},endTime={}", jobId,df.