美文网首页
Quartz 源码解析(三) —— JobDetail、Trig

Quartz 源码解析(三) —— JobDetail、Trig

作者: icameisaw | 来源:发表于2018-09-02 17:31 被阅读621次

大概内容

  • 解析JobDetail
  • JobBuilder和Builder Pattern
  • 类比解析Trigger

关于JobDetail

JobDetail相关类

JobDetailImpl.java

JobDetailImpl是接口JobDetail的唯一实现类,本质上来说是一个Java Bean,这里主要是要理解各个属性的意思。

public class JobDetailImpl implements Cloneable, java.io.Serializable, JobDetail {

    // Job的名称
    private String name;

    // Job的分组
    private String group = Scheduler.DEFAULT_GROUP;

    // Job的描述
    private String description;

    // 执行Job业务逻辑的对应实体类的Class引用
    private Class<? extends Job> jobClass;

    // 保存关于Job的信息,根据业务逻辑自己放进去
    private JobDataMap jobDataMap;

    // 当没有绑定Trigger的情况,是否保存Job
    private boolean durability = false;

    // Job是否可从“恢复”情况下再次执行
    private boolean shouldRecover = false;

    // 封装了name和group,作为JobDetail的唯一标识
    // 用空间来换取时间和可读性的策略
    private transient JobKey key = null;
}

JobKey

JobKey没有特殊的代码逻辑,都是借助于父类Key<JobKey>的能力。

public final class JobKey extends Key<JobKey> {

    public JobKey(String name) {
        super(name, null);
    }

    public JobKey(String name, String group) {
        super(name, group);
    }

    // 其他代码

}

public class Key<T>  implements Serializable, Comparable<Key<T>> {

    /**
     * The default group for scheduling entities, with the value "DEFAULT".
     */
    public static final String DEFAULT_GROUP = "DEFAULT";

    private final String name;
    private final String group;

    /**
     * name不允许为空,group没有指定值则自动赋值为"DEFAULT"
     */
    public Key(String name, String group) {
        if(name == null)
            throw new IllegalArgumentException("Name cannot be null.");
        this.name = name;
        if(group != null)
            this.group = group;
        else
            this.group = DEFAULT_GROUP;
    }

    // 其他代码
    /**
     * 先比较group,再比较name
     */
    public int compareTo(Key<T> o) {

        if(group.equals(DEFAULT_GROUP) && !o.group.equals(DEFAULT_GROUP))
            return -1;
        if(!group.equals(DEFAULT_GROUP) && o.group.equals(DEFAULT_GROUP))
            return 1;

        int r = group.compareTo(o.getGroup());
        if(r != 0)
            return r;

        return name.compareTo(o.getName());
    }

    /**
     * 如果name为空,那么在JobBuilder或者TriggerBuilder的build()方法会调用此方法根据group自动生成一个name。
     */    
    public static String createUniqueName(String group) {
        if(group == null)
            group = DEFAULT_GROUP;

        String n1 = UUID.randomUUID().toString();
        String n2 = UUID.nameUUIDFromBytes(group.getBytes()).toString();

        return String.format("%s-%s", n2.substring(24), n1);
    }
}

JobDataMap

JobDataMap提供了一个Map<String, Object>的对象,我们可以在管理或者执行Job的过程中保存或者查询一些自定义的信息。
在第一篇的案例里面,是通过JobBuilder的usingJobData()方法放进去一些信息。

public class JobDataMap extends StringKeyDirtyFlagMap implements Serializable {

    public JobDataMap() {
        super(15);
    }

    public JobDataMap(Map<?, ?> map) {
        this();
        @SuppressWarnings("unchecked") // casting to keep API compatible and avoid compiler errors/warnings.
        Map<String, Object> mapTyped = (Map<String, Object>)map;
        putAll(mapTyped);

        // When constructing a new data map from another existing map, we should NOT mark dirty flag as true
        // Use case: loading JobDataMap from DB
        clearDirtyFlag();
    }

    /**
     * 提供很多个重载不同数据类型的putAsString()方法,都是父类对StringKeyDirtyFlagMap的简单封装
     */
    public void putAsString(String key, boolean value) {
        String strValue = Boolean.valueOf(value).toString();

        super.put(key, strValue);
    }

    // 其他代码

    /**
     * 提供很多个不同数据类型的getXXX()方法,都是父类对StringKeyDirtyFlagMap的简单封装
     */
    public boolean getBooleanValueFromString(String key) {
        Object obj = get(key);
        return Boolean.valueOf((String) obj);
    }

    public boolean getBooleanValue(String key) {
        Object obj = get(key);
        if(obj instanceof String) {
            return getBooleanValueFromString(key);
        } else {
            return getBoolean(key);
        }
    }
    // 其他代码
}

关于JobBuilder

Builder Pattern

封装一个产品的构造过程,并允许按步骤构造,并且可以改变过程(这和只有一个步骤的工厂模式不同)。与工厂模式相比,采用Builder Pattern来创建对象的Client,需要具备更多的领域知识。

JobBuilder

  • 将JobDetail的属性都封装起来
  • 允许JobDeatil通过多个步骤来创建,并且可以改变过程或者顺序
// 3.创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(RAMJob.class)
        .withDescription("this is a ram job") //job的描述
        .withIdentity("ramJob", "ramGroup") //job 的name和group
        .build();

JobBuilder的属性和JobDetail的属性基本一致,这样得以在build()方法里面,完成对JobDetail进行创建。

// JobBuilder.java
public JobDetail build() {
    JobDetailImpl job = new JobDetailImpl();

    job.setJobClass(jobClass);
    job.setDescription(description);
    if(key == null)
        key = new JobKey(Key.createUniqueName(null), null);
    job.setKey(key);
    job.setDurability(durability);
    job.setRequestsRecovery(shouldRecover);

    if(!jobDataMap.isEmpty())
        job.setJobDataMap(jobDataMap);

    return job;
}

JobBilder的大部分方法都是返回自身的引用,这样得以多个步骤的方式来完善JobDetail的属性内容。
JobBuilder.withIdentity()主要是设置属性值。
JobBuilder.usingJobData()主要是设置JobDataMap字段。

public class JobBuilder {
    public JobBuilder withIdentity(String name)
    public JobBuilder withIdentity(String name, String group)
    public JobBuilder withIdentity(JobKey jobKey)
    public JobBuilder withDescription(String jobDescription)
    public JobBuilder ofType(Class<? extends Job> jobClazz)
    public JobBuilder requestRecovery()
    public JobBuilder requestRecovery(boolean jobShouldRecover)
    public JobBuilder storeDurably()
    public JobBuilder storeDurably(boolean jobDurability)
    public JobBuilder usingJobData(String dataKey, String value)
    public JobBuilder usingJobData(String dataKey, Integer value)
    public JobBuilder usingJobData(String dataKey, Long value)
    public JobBuilder usingJobData(String dataKey, Float value)
    public JobBuilder usingJobData(String dataKey, Double value)
    public JobBuilder usingJobData(String dataKey, Boolean value)
    public JobBuilder usingJobData(JobDataMap newJobDataMap)
    public JobBuilder setJobData(JobDataMap newJobDataMap)
}

类比解析Trigger

相关类的类图

Trigger相关类

TriggerBuilder

TriggerBuilder是一个泛型类,与JobBuilder有点不一样,而且创建Trigger实例的动作委托给了ScheduleBuilder类。ScheduleBuilder,这次不顾名思义了,它作为一个生成器,不是要生成Scheduler类,而是要生成MutableTrigger实例。
在第一篇的案例里面,ScheduleBuilder使用的具体对象是CronScheduleBuilder。

// 4.创建Trigger
Trigger trigger = TriggerBuilder.newTrigger().withDescription("")
    .withIdentity("ramTrigger", "ramTriggerGroup")
    .startAt(new Date()) // 默认当前时间启动
    .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")) // 两秒执行一次
    .usingJobData("triggerKey", "some important information to save")
    .build();
  • TriggerBuilder.java
public class TriggerBuilder<T extends Trigger> {

    private TriggerKey key;
    private String description;
    private Date startTime = new Date();
    private Date endTime;
    private int priority = Trigger.DEFAULT_PRIORITY;
    private String calendarName;
    private JobKey jobKey;
    private JobDataMap jobDataMap = new JobDataMap();

    private ScheduleBuilder<?> scheduleBuilder = null;

    private TriggerBuilder() {

    }

    public T build() {
      if(scheduleBuilder == null)
          scheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
      MutableTrigger trig = scheduleBuilder.build();

      trig.setCalendarName(calendarName);
      trig.setDescription(description);
      trig.setStartTime(startTime);
      trig.setEndTime(endTime);
      if(key == null)
          key = new TriggerKey(Key.createUniqueName(null), null);
      trig.setKey(key);
      if(jobKey != null)
          trig.setJobKey(jobKey);
      trig.setPriority(priority);

      if(!jobDataMap.isEmpty())
          trig.setJobDataMap(jobDataMap);

      return (T) trig;
    }
    // 其他代码
}    
  • CronScheduleBuilder.java
public class CronScheduleBuilder extends ScheduleBuilder<CronTrigger> {

    private CronExpression cronExpression;
    private int misfireInstruction = CronTrigger.MISFIRE_INSTRUCTION_SMART_POLICY;

    protected CronScheduleBuilder(CronExpression cronExpression) {
        if (cronExpression == null) {
            throw new NullPointerException("cronExpression cannot be null");
        }
        this.cronExpression = cronExpression;
    }

    /**
     * Build the actual Trigger -- NOT intended to be invoked by end users, but
     * will rather be invoked by a TriggerBuilder which this ScheduleBuilder is
     * given to.
     *
     * @see TriggerBuilder#withSchedule(ScheduleBuilder)
     */
    @Override
    public MutableTrigger build() {
        CronTriggerImpl ct = new CronTriggerImpl();
        ct.setCronExpression(cronExpression);
        ct.setTimeZone(cronExpression.getTimeZone());
        ct.setMisfireInstruction(misfireInstruction);
        return ct;
    }

    // 其他代码

}

系列文章

相关文章

网友评论

      本文标题:Quartz 源码解析(三) —— JobDetail、Trig

      本文链接:https://www.haomeiwen.com/subject/zhbmwftx.html