Quartz中,Job组件包含我们具体需要执行的业务代码。Quartz还具有Job的串行控制、维护状态参数等功能,下面我们详细介绍。
package com.gacfox.demoquartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DemoJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("任务执行 " + sdf.format(date));
}
}
// 创建任务实例
JobDetail jobDetail = JobBuilder
.newJob(DemoJob.class)
.withIdentity("jobDetail", "demoGroup")
.build();
Quartz中的Job组件需要实现Job
接口,具体使用时,需要对其创建JobDetail
实例,然后载入调度器。
默认情况下,Job会并发执行,也就是说之前的Job代码还没执行完,再次触发还会在新的线程中执行。有时我们需要控制Job串行执行,这可以用@DisallowConcurrentExecution
注解实现。
@DisallowConcurrentExecution
public class DemoJob implements Job {
// ...
}
Quartz中Job运行时可以维护一些参数,存在于一个JobDataMap对象中。例子如下:
package com.gacfox.demoquartz;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class DemoJob implements Job {
private String key;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Job参数:key [" + key + "]");
}
public void setKey(String key) {
this.key = key;
}
}
// 创建任务实例
JobDetail jobDetail = JobBuilder
.newJob(DemoJob.class)
.withIdentity("jobDetail", "demoGroup")
.usingJobData("key", "gacfox")
.build();
上面代码中,我们设置了一个字符串参数,键为key
,值为gacfox
。Job中,我们编写了一个set
方法,用于接收该参数,每次Job执行时将其打印出来。参数实际上以键值对形式存储在JobDataMap
对象中,我们可以通过jobExecutionContext.getJobDetail().getJobDataMap()
获取。
如上配置我们会发现,Job中只能读取参数,而主动设置这些参数是无效的,如果希望Job能够修改并持久化参数,这实际上是试图创建有状态Job,当然Quartz也支持有状态Job。
之前我们为Job设置了参数,但实际上这些参数每次都会被重新设置,因此上面的配置中Job每次执行时没有状态这个概念。然而如果Job中读取之前修改的参数值、并再次修改这些参数后存储,那么其实这就是一个有状态的Job。
下面是一个有状态Job例子,我们为Job设置了一个变量count
,在Job每次执行时都对其加1
,并输出当前是第几次执行:
package com.gacfox.demoquartz;
import org.quartz.*;
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class DemoJob implements Job {
private Integer count;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
count++;
jobExecutionContext.getJobDetail().getJobDataMap().put("count", count);
System.out.println("Job参数:已执行次数 count [" + count + "]");
}
public void setCount(Integer count) {
this.count = count;
}
}
注意这里我们为Job设置了@PersistJobDataAfterExecution
注解,该注解标明此Job中的参数会被持久化,否则执行时参数会被默认覆盖为JobDataMap
的初始值。此外有状态Job一般都是串行执行的,因此我们还指定了@DisallowConcurrentExecution
注解,并发执行可能造成状态数据混乱。
有状态Job的配置例子如下。
// 创建任务实例
JobDetail jobDetail = JobBuilder
.newJob(DemoJob.class)
// 这里设置任务名和任务组名,用于和触发器关联
.withIdentity("jobDetail", "demoGroup")
.storeDurably(true)
.usingJobData("count", 0)
.build();
代码中,我们除了设置JobDataMap
,还设置了storeDurably(true)
,表示持久化状态数据。