乐趣区

关于java: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 办法创立新的对象来实现的:

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

退出移动版