我们给了scheduler 一个JobDetail 实例,而我们再创建JobDetail实例的时候,告诉了它我们的Job的类型,所以,scheduler也是知道我们job的类型的。
每次scheduler在执行Job的时候,在执行job的execute方法之前,都会创建一个我们job的实例,在execute方法执行结束后,job实例会被GC(回收)
这样就会导致两个结果,1、必须为我们自己的job提供一个无参的构造函数 2、无法记录job执行的状态(两次execute之间)。
那么问题来了,如果想要记录job执行状态,怎么办?答案是JobDataMap
JobDataMap是JobDetail的一个属性
JobDataMap其实就是一个Map的实现,可以看成是map,只是提供了一些更加方便的存取方法。JobDataMap存放的数据必须是可序列化的。
JobDetail jobDetail = JobBuilder.newJob(MyJob.class) .withIdentity("job1","jobgroup") .usingJobData("name","张三") .usingJobData("time","2018") .build();
如上代码,添加了name和time两个属性,我们可以在Job中获取到
@Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("定时任务正在执行" + context.getJobDetail().getJobDataMap().getString("time")); }
如果在我们自己的Job类中,我们自己提供了setter方法,setter方法的名称必须和JobDataMap中属性名称相对应,那么,Quartz的默认JobFactory会自动装配这些setter方法所对应的Job的属性值。这就避免了从JobExecutionContext中获取值得方法。如下
public class MyJob implements Job { public String time; public void setTime(String time) { this.time = time; } @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("定时任务正在执行" + time); } }
上面两种从JobDataMap中取值得方法中,第一种方法,Job类代码简洁,但是execute中代码比较繁琐。
第二种方法,execute中代码简洁了,但是Job类代码比原来多了。至于怎么选择,看自己爱好了。
由于JobDetai和Trigger都有JobDataMap,所以,当使用第二种方法时,如果在设置值时,JobDetail和Trigger的JobDataMap有相同的Key,则Trigger的Key会覆盖JobDetail的Key。同理如果使用JobExecuteContext.getMergeJobDataMap来取值(即两个JobDataMap合并),那么,Trigger的Key同样会覆盖JobDetail的Key
Job还有两个注解可以使用,一般是成对出现(要么都使用,要么都不用)
@DisallowConcurrentExecution 顾名思义,就是不允许多个job同时执行。
@PersistJobDataAfterExecution 每次执行完一个Job后,更新JobDetail的JobDataMap的值。那么为了防止并发出现问题,这两个注解都是同时使用