background

ElasticJob is a task scheduling framework based on Quartz. The LiteJob class contains two member variables, but there are data for these two member variables during task scheduling.

When exactly are they assigned?

When I used Quartz, any custom Job class that contained member variables was initialized in the no-argument constructor. Job implementation classes are not designed to contain member variables.

ElasticJob scheduling process

ElasticJob scheduling starts with the Init method of the JobScheduler class and returns to the Quartz task creation process. At the bottom, a LiteJob task class is created using the API.

public void init() { LiteJobConfiguration liteJobConfigFromRegCenter = schedulerFacade.updateJobConfiguration(liteJobConfig); JobRegistry.getInstance().setCurrentShardingTotalCount(liteJobConfigFromRegCenter.getJobName(), liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getShardingTotalCount()); JobScheduleController jobScheduleController = new JobScheduleController( createScheduler(), createJobDetail(liteJobConfigFromRegCenter.getTypeConfig().getJobClass()), liteJobConfigFromRegCenter.getJobName()); JobRegistry.getInstance().registerJob(liteJobConfigFromRegCenter.getJobName(), jobScheduleController, regCenter); schedulerFacade.registerStartUpInfo(! liteJobConfigFromRegCenter.isDisabled()); jobScheduleController.scheduleJob(liteJobConfigFromRegCenter.getTypeConfig().getCoreConfig().getCron()); }Copy the code

The createJobDetail method here Bridges ElasticJob and 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; }Copy the code

This code is the familiar Quartz scheduling API. The definition of LiteJob is very simple:

public final class LiteJob implements Job { @Setter private ElasticJob elasticJob; @Setter private JobFacade jobFacade; @Override public void execute(final JobExecutionContext context) throws JobExecutionException { JobExecutorFactory.getJobExecutor(elasticJob, jobFacade).execute(); }}Copy the code

It consists of two member variables whose assignments are stored in JobDataMap in the createJobDetail method. The data key matches the variable name.

Then when Quartz performs the task scheduling, the instance that created the instance automatically completes the assignment of the member variable.

Quartz The process of creating a Job

PropertySettingJobFactory create instances when the Job, can obtain the data in the JobDataMap, through reflection set instance member variables.

The specific source code is:

 @Override
 public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {

     Job job = super.newJob(bundle, scheduler);
     
     JobDataMap jobDataMap = new JobDataMap();
     jobDataMap.putAll(scheduler.getContext());
     jobDataMap.putAll(bundle.getJobDetail().getJobDataMap());
     jobDataMap.putAll(bundle.getTrigger().getJobDataMap());

     setBeanProps(job, jobDataMap);
     
     return job;
 }
Copy the code

SetBeanProps sets the properties of the Job instance class. It will traverse all the data in JobDataMap and then find the corresponding setter method based on the data type and key.

protected void setBeanProps(Object obj, JobDataMap data) throws SchedulerException { for (Iterator<? > entryIter = data.getWrappedMap().entrySet().iterator(); entryIter.hasNext();) { Map.Entry<? ,? > entry = (Map.Entry<? ,? >)entryIter.next(); String name = (String)entry.getKey(); String c = name.substring(0, 1).toUpperCase(Locale.US); String methName = "set" + c + name.substring(1); java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs); Class<? > paramType = null; Object o = null; try { paramType = setMeth.getParameterTypes()[0]; o = entry.getValue(); Object parm = null; if (paramType.isPrimitive()) { if (paramType.equals(int.class)) { if (o instanceof String) { parm = Integer.valueOf((String)o); } else if (o instanceof Integer) { parm = o; } } else if (paramType.equals(long.class)) { if (o instanceof String) { parm = Long.valueOf((String)o); } else if (o instanceof Long) { parm = o; } } else if (paramType.equals(float.class)) { if (o instanceof String) { parm = Float.valueOf((String)o); } else if (o instanceof Float) { parm = o; } } else if (paramType.equals(double.class)) { if (o instanceof String) { parm = Double.valueOf((String)o); } else if (o instanceof Double) { parm = o; } } else if (paramType.equals(boolean.class)) { if (o instanceof String) { parm = Boolean.valueOf((String)o); } else if (o instanceof Boolean) { parm = o; } } else if (paramType.equals(byte.class)) { if (o instanceof String) { parm = Byte.valueOf((String)o); } else if (o instanceof Byte) { parm = o; } } else if (paramType.equals(short.class)) { if (o instanceof String) { parm = Short.valueOf((String)o); } else if (o instanceof Short) { parm = o; } } else if (paramType.equals(char.class)) { if (o instanceof String) { String str = (String)o; if (str.length() == 1) { parm = Character.valueOf(str.charAt(0)); } } else if (o instanceof Character) { parm = o; } } } else if ((o ! = null) && (paramType.isAssignableFrom(o.getClass()))) { parm = o; } setMeth.invoke(obj, new Object[]{ parm }); }Copy the code

This explains why the LiteJob class contains two member variables, but instances are created normally and properties are assigned normally.

The revelation of

I found my own blind spot in Quartz by tracking the source code for ElasticJob.

You’ll have another way to set Job member variables when you have a chance to use Quartz again. LiteJob is an elegant class definition that you can learn from.