当前位置: 首页 > 后端技术 > Java

Quartz-Job&JobDetail

时间:2023-04-01 23:39:26 Java

今天我们分析一下Quartz中三个与job相关的概念:JobJobDetailJobDataMapJob上一篇已经简单分析过:Job是一个任务接口,包括一个execute方法。Job类似于JDKTimer中的TimerTask,是提供给应用程序实现任务逻辑的API。应用层需要关注的其实是Job接口。Job需要实现的业务逻辑在Job接口的实现类的execute方法中实现。JobDetailJobDetail用于保存Job实现类的类名,最终绑定到任务调度器的不是Job而是JobDetail。JobDetail接口不需要应用程序关注,也不需要应用层实现。Quartz提供了一个JobDetail实现类JobDetailImpl,由JobBuilder创建。JobDetail有一个重要的属性key,类型为JobKey,相当于任务的key值。JobDetail在任务调度器Schedule中注册时,键值不能重复。在整个任务调度过程中,Quartz通过Jobkey来唯一标识JobDetail。不允许在不指定覆盖的情况下尝试在调度程序中注册具有重复键的JobDetail。通过JobBuiler的withIdentity方法可以指定JobKey,该方法接收name或者name+group参数来唯一确定一个job的JobDetail。如果在JobDetail创建过程中没有指定JobKey,Quartz会通过UUID的方式为任务生成一个唯一的键值。因此,同一个Job实现类(即同一个任务)可以通过不同的JobKey值注册到任务调度器中,绑定不同的触发器执行!Job调度方法Quartz的任务执行线程通过JobDetail持有的Job实现类的类名调用newInstance方法创建新对象来调度Job任务:为什么JobDetailImpl持有Job实现类的类名?,而不是直接持有Job对象,直接通过对象执行任务?我个人认为这样做的目的之一是实现多线程任务调度时Job对象的隔离(数据安全)。因为如果直接持有Job实现类的对象,就意味着任务调度器每次触发执行任务,都是通过Job实现类的同一个对象来执行任务,所以Job实现类的状态必须be是当前任务执行完成后的状态。在这种情况下,客户端程序员必须注意Job实现类的状态处理。稍有不慎就可能导致意想不到的结果。每个任务线程通过一个新的任务对象执行任务,也可以避免多线程任务调度过程中的线程安全问题。这个实现方法其实就是要求我们的Job实现类必须提供一个无参的构造函数,否则Quartz在创建任务对象的时候会抛出SchedulerException。JobDataMapJobDataMap是一组无限的数据集。通过JobDataMap在创建任务的时候可以给任务传递参数,在任务执行的时候可以拿到数据集。比如我们前面说过,一个Job实现类可以通过创建多个不同的JobDetails(通过不同的JobKey来区分)来绑定到任务调度器schedule。在这种情况下,可以通过JobDataMap向JobDetail传递不同的参数来区分它们的行为。Quartz官网的例子“SalesReportForJoe”和“SalesReportForMike”就是这个意思。举例:publicclassHelloJobimplementsJob{@Overridepublicvoidexecute(JobExecutionContextjobExecutionContext)throwsJobExecutionException{log.info("Idon'tknowwantshouldido..."+Thread.currentThread().getId()+"andI我是:“+这个+”和工作名=“+jobExecutionContext.getJobDetail().getKey());JobDataMapjobDataMap=jobExecutionContext.getJobDetail().getJobDataMap();if(jobDataMap!=null){log.info("JD:"+jobDataMap.get("JD"));}}publicstaticvoidmain(String[]args){log.info("我正在运行...");JobDetailjobDetail=newJob(HelloJob.class).withDescription("Thisismyfirstquartzjob").usingJobData("JD","ThisisJD").withIdentity("MyJob").build();JobDetailjobDetail1=newJob(HelloJob.class).withDescription("Thisismyfirstquartzjob").usingJobData("JD","ThisisJD1").withIdentity("MyJob1").build();触发器trigger=newTrigger().withIdentity("myTriggger","MyGroup").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(20).repeatForever()).build();触发器trigger1=newTrigger().withIdentity("myTriggger1","MyGroup1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(20).repeatForever()).build();尝试{Schedulersche=newStdSchedulerFactory().getScheduler();sche.scheduleJob(jobDetail,trigger);秒che.scheduleJob(jobDetail1,trigger1);sche.start();}catch(Exceptione){e.printStackTrace();}log.info("我完成了");}}创建一个HelloJob实现Job接口的execute方法,这个方法只是打印当前job的threadid,当前Job对象,以及获取到的JobDataMap运行结果:22:32:36.974[DefaultQuartzScheduler_Worker-1]INFOcom.example.demo.quartz.HelloJob-我不知道我应该做什么...11我是:com.example.demo.quartz.HelloJob@77e596d4和jobname=DEFAULT.MyJob22:32:36.974[DefaultQuartzScheduler_Worker-1]INFOcom.example.demo.quartz.HelloJob-JD:ThisisJD22:32:36.974[DefaultQuartzScheduler_Worker-2]INFOcom.example.demo.quartz.HelloJob-我不知道我应该做什么...12我是:com.example.demo.quartz.HelloJob@239bdf36和jobname=DEFAULT.MyJob122:32:36.974[DefaultQuartzScheduler_Worker-2]INFOcom.example.demo.quartz.HelloJob-JD:ThisisJD120秒后:22:32:56.830[DefaultQuartzScheduler_Worker-3]INFOcom.example.demo.quartz.HelloJob-我不知道我应该做什么...13我是:com.example.demo.quartz.HelloJob@78a13114andjobname=DEFAULT.MyJob22:32:56.830[DefaultQuartzScheduler_Worker-3]INFOcom.example.demo.quartz.HelloJob-JD:ThisisJD22:32:56.831[DefaultQuartzScheduler_Worker-4]INFOcom.example.demo.quartz.HelloJob-我不知道我应该做什么...14我是:com.example.demo.quartz.HelloJob@1a9fa98f和jobname=DEFAULT.MyJob122:32:56.831[DefaultQuartzScheduler_Worker-4]INFOcom.example.demo.quartz.HelloJob-JD:ThisisJD1从运行结果可以得出如下结论:Quartz每次从线程池中获取不同的线程来执行任务。每次调度任务时,执行该任务的Job对象都不同。将任务绑定到任务调度器时,通过设置JobDataMap将参数传递给任务对象,任务执行时即可获取参数。一个Job实现类可以通过不同的JobDetails多次绑定同一个TaskScheduler的不同触发器,从而可以被不同的触发规则触发执行。PreviousQuartz-SimpleThreadPoolNextQuartz-触发器和RAMJobStore