JobDetail实例,而且,它经过job的类代码引用这个job来执行。每次调度器执行job时,它会在调用job的execute(..)方法以前建立一个他的实例。这就带来了两个事实:1、job必须有一个不带参数的构造器,2、在job类里定义数据成员并无意义,由于在每次job执行的时候他们的值会被覆盖掉。安全
你可能如今想要问“我怎样给一个job实例提供属性/配置?”和“在几回执行间我怎样能跟踪job的状态?”这些问题的答案是同样的:用JobDataMap- JobDetail对象的一部分。并发
JobDataMap可以支持任何序列化的对象,当job执行时,这些对象可以在job实例中可用。JobDataMap实现了Java Map接口,它有一些附加的方法,这些方法用来储存和跟踪简单类型的数据。对象
以下代码能够很快地给job增长JobDataMap:接口
jobDetail.getJobDataMap().put("jobSays", "Hello World!");进程
jobDetail.getJobDataMap().put("myFloatValue", 3.141f);ip
jobDetail.getJobDataMap().put("myStateData", new ArrayList());文档
在job执行时,咱们能够在job里经过以下代码获得JobDataMap:get
public class DumbJob implements Job {io
public DumbJob() {class
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);
}
}
若是用一个持久JobStore(在指南JobStore章节讨论),咱们就应该注意在JobDataMap里放些什么,由于在它里面的对象将会被序列化,而且这些对象会所以产生一些class-versioning问题。明显的,标准Java类型应该是很安全的,可是,任什么时候候某人改变了一个你已经序列化的实例的类的定义时,咱们就要注意不可以破坏兼容性了。在这个方面的进一步信息能够在Java Developer Connection Tech Tip: Serialization In The Real World里找到。咱们能把JDBC-JobStore和JobDataMap放到一个模式里,在那里,只有简单类型和String型能被储存在Map里,从而消去任何之后的序列化问题。
Stateful vs. Non-Stateful Jobs
触发器也有与它们关联的JobDataMaps。假设咱们有一个储存在调度器里被多个触发器关联的job,然而,对于每一个独立的触发器,我想提供给job不一样的数据输入,在这个时候,JobDataMaps就颇有用了。
在job执行期间,JobDataMaps可以在JobExecutionContext里得到。JobDataMap融合在Trigger和JobDetail类里,JobDataMap里面的值可以利用key来更新。
如下例子显示,在job执行期间从JobExecutionContext里的JobDataMap获得数据:
public class DumbJob implements Job {
public DumbJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException
{
String instName = context.getJobDetail().getName();
String instGroup = context.getJobDetail().getGroup();
JobDataMap dataMap = context.getJobDataMap(); // 注意:不一样于之前的例子
String jobSays = dataMap.getString("jobSays");
float myFloatValue = dataMap.getFloat("myFloatValue");
ArrayList state = (ArrayList)dataMap.get("myStateData");
state.add(new Date());
System.err.println("Instance " + instName + " of DumbJob says: " + jobSays);
}
}
如今,关于job状态数据的一些附加要点:一个job实例能定义为"有状态的"或者"无状态的"。无状态的jobs仅当它们在被加入到调度器里时才存储JobDataMap。这就意味着,在jobs执行期间对JobDataMap里数据的任何改变都会丢失,下次执行时job将看不到这些数据。你可能会猜到,一个有状态的job就是它的反面例子-它的JobDataMap是在每次执行完job后再次储存的。一个缺点就是有状态的job不可以并发执行。换句话说,若是job是有状态的,一个触发器尝试触发这个已经执行了的job时,这个触发器就会等待直到此次执行结束。
用实现
咱们可以建立一个单独的job类,而且经过建立多个JobDetails实例在调度器里储存不少它的“实例定义”,每一个都有它本身的属性集和JobDataMap ,把它们都加入到调度器里。
当一个触发器触发时,与它关联的job就是经过配置在调度器上的JobFactory 来实例化的。默认的JobFactory 简单的调用在job类上的newInstance()方法,你可能想要建立本身的JobFactory实现来完成一些本身想要的事情,如:拥有应用程序的IoC或者DI容器进程/初始化job实例。
这儿有一个其余属性的总结,这些属性是经过JobDetail对象为一个job实例定义的。
最后,咱们来看看Job.execute(..)方法的一些细节。你可以从execute方法里抛出的仅有的异常类型就是JobExecutionException。由于这样,咱们应该使用try-catch块包围整个execute方法内容。咱们还应该花一些时间看看JobExecutionException文档。当job执行发生异常时,经过设置JobExecutionException,可让此job再次进入调度器或者从此再也不运行。