Quartz - Job & JobDetail

我们今天分析Quartz中与作业相关的3个概念:

1. Job

2. JobDetail

3. JobDataMap

#### Job

上一篇文章已经简单做过分析:Job是任务接口,包含一个execute方法。Job与JDK Timer中的TimerTask类似,是提供给应用实现任务逻辑的API。

应用层需要关注的其实就是这个Job接口,作业需要实现的业务逻辑就在Job接口的实现类的execute方法中实现。

#### JobDetail

JobDetail用来持有Job实现类的类名,最终绑定到任务调度器中的不是Job而是JobDetail。JobDetail接口不需要应用关心、也不需要应用层实现,Quartz提供了一个JobDetail的实现类JobDetailImpl,通过JobBuilder来创建。

JobDetail有一个类型为JobKey的重要属性key,相当于是该任务的键值,JobDetail注册到任务调度器Schedule中的时候,key值不允许重复。***整个任务调度过程中,Quartz都是通过Jobkey来唯一识别JobDetail的。试图将重复键值的JobDetail注册到任务调度器中而不指定覆盖的话,是不被允许的。***

JobKey可以通过JobBuiler的withIdentity方法指定,该方法接收name或name+group参数,从而唯一确定一个任务JobDetail。

如果在JobDetail创建过程中不指定JobKey的话,Quartz会通过UUID的方式为该任务生成一个唯一的key值。

***所以,同一个Job实现类(也就是同一个任务),可以通过不同的JobKey值注册到任务调度器中、绑定不同的触发器执行!***

#### Job的调度方式

Quartz的任务执行线程在调度Job任务的时候,是通过JobDetail持有的Job实现类的类名调用newInstance方法创建新的对象来实现的:

![image.png](/img/bVc58z3)

JobDetailImpl为什么会持有Job实现类的类名、而不是直接持有Job对象、通过该对象直接执行任务?

个人认为这么做的目的之一是为了实现多线程任务调度过程中Job的对象的隔离性(数据安全)。因为如果直接持有Job实现类的对象的话,就意味着每次任务调度器触发并执行该任务的时候,都是通过相同的Job实现类的对象来执行任务的,则Job实现类的状态一定是当前任务执行完成之后的状态,这样的话就要求客户端程序员务必关注对Job实现类状态的处理,稍有不慎可能就会导致意想不到的结果。

每一个任务线程都是通过新的任务对象来执行任务,也可以避免多线程任务调度过程中的线程安全性问题。

***这种实现方式其实也要求我们的Job实现类必须提供无参构造器,否则Quartz在创建任务对象的时候会抛出SchedulerException异常。***

#### JobDataMap

JobDataMap是不限个数的一组数据集,可以通过JobDataMap在创建任务的时候传递参数给该任务、在任务执行的时候可以获取到该数据集。

比如我们前面说过,一个Job实现类可以通过创建多个不同的JobDetail(通过不同的JobKey区分)绑定到任务调度器schedule中,这种情况下可以就通过JobDataMap传递不同的参数给JobDetail从而区分他们的行为。Quartz官网中举例说明的“SalesReportForJoe”、“SalesReportForMike”就是这个意思。

举例:

```

public class HelloJob implements Job {

@Override

public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

log.info("I dont know want should i do ..."+Thread.currentThread().getId()+

" and I am :" + this + " and jobname="+jobExecutionContext.getJobDetail().getKey());

JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();

if(jobDataMap!=null){

log.info("JD:"+jobDataMap.get("JD"));

}

}

public static void main(String[] args) {

log.info("I am running...");

JobDetail jobDetail = newJob(HelloJob.class)

.withDescription("This is my first quartz job")

.usingJobData("JD","This is JD")

.withIdentity("MyJob")

.build();

JobDetail jobDetail1 = newJob(HelloJob.class)

.withDescription("This is my first quartz job")

.usingJobData("JD","This is JD1")

.withIdentity("MyJob1")

.build();

Trigger trigger = newTrigger()

.withIdentity("myTriggger","MyGroup")

.startNow()

.withSchedule(simpleSchedule()

.withIntervalInSeconds(20)

.repeatForever())

.build();

Trigger trigger1 = newTrigger()

.withIdentity("myTriggger1","MyGroup1")

.startNow()

.withSchedule(simpleSchedule()

.withIntervalInSeconds(20)

.repeatForever())

.build();

try {

Scheduler sche = new StdSchedulerFactory().getScheduler();

sche.scheduleJob(jobDetail,trigger);

sche.scheduleJob(jobDetail1,trigger1);

sche.start();

}catch(Exception e){

e.printStackTrace();

}

log.info("i am done");

}

}

```

创建HelloJob实现Job接口的execute方法,该方法只是打印当前作业的线程id、当前Job对象、以及获取到的JobDataMap。

运行结果:

```

22:32:36.974 [DefaultQuartzScheduler_Worker-1] INFO com.example.demo.quartz.HelloJob - I dont know want should i do ...11 and I am :com.example.demo.quartz.HelloJob@77e596d4 and jobname=DEFAULT.MyJob

22:32:36.974 [DefaultQuartzScheduler_Worker-1] INFO com.example.demo.quartz.HelloJob - JD:This is JD

22:32:36.974 [DefaultQuartzScheduler_Worker-2] INFO com.example.demo.quartz.HelloJob - I dont know want should i do ...12 and I am :com.example.demo.quartz.HelloJob@239bdf36 and jobname=DEFAULT.MyJob1

22:32:36.974 [DefaultQuartzScheduler_Worker-2] INFO com.example.demo.quartz.HelloJob - JD:This is JD1

20秒后:

22:32:56.830 [DefaultQuartzScheduler_Worker-3] INFO com.example.demo.quartz.HelloJob - I dont know want should i do ...13 and I am :com.example.demo.quartz.HelloJob@78a13114 and jobname=DEFAULT.MyJob

22:32:56.830 [DefaultQuartzScheduler_Worker-3] INFO com.example.demo.quartz.HelloJob - JD:This is JD

22:32:56.831 [DefaultQuartzScheduler_Worker-4] INFO com.example.demo.quartz.HelloJob - I dont know want should i do ...14 and I am :com.example.demo.quartz.HelloJob@1a9fa98f and jobname=DEFAULT.MyJob1

22:32:56.831 [DefaultQuartzScheduler_Worker-4] INFO com.example.demo.quartz.HelloJob - JD:This is JD1

```

从运行结果我们可以得到以下结论:

1. Quartz每次从线程池获取不同的线程来执行任务。

2. 每次任务调度时,执行任务的Job对象不同。

3. 绑定任务到任务调度器时,通过设置JobDataMap传递参数到任务对象,在任务执行时能获取到该参数。

4. 一个Job实现类可以通过不同的JobDetail多次绑定到同一个任务调度器的不同触发器上,从而被不同的触发规则触发执行。

上一篇 [Quartz - SimpleThreadPool](https://segmentfault.com/a/1190000043344878)

下一篇 [Quartz - Trigger & RAMJobStore](https://segmentfault.com/a/1190000043391831)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值