Quartz is no doubt the most popular open source Java library for job scheduling. It’s been around for many years and includes advanced features like clustering.Its API is a bit clunky though, especially for simple cases where you just want to schedule a job using a cron expression. As you can see from its tutorial you need not just a Job class but also a JobDetail and a Trigger before you can pass it to the scheduler. Additionally, and this is the main pain point, you need to pass a Job class, not an instance, so your Job implementation needs a default no-arg constructor, and you can’t prepare the instance by e.g. invoking setter methods before scheduling it. Parameters and state can be passed using a JobDataMap (see example) but that’s not very intuitive and doesn’t make for clean code. For this reason I wrote a little facade called Cron that lets you schedule a job by passing a Job instance and a cron expression, nothing more. Here’s a trivial example of how you can execute a job every 5 seconds: Cron cron = new Cron(new StdSchedulerFactory());
Job job = new Job() {
public void execute(JobExecutionContext context) {
System.out.println("job executed");
}
};
cron.schedule(job, "*/5 * * * * ?");
cron.start();
System.in.read();
cron.shutdown();
Here’s the Cron class. Internally it uses a custom JobFactory to recycle the provided job instances, rather than creating new instances from Job classes like Quartz does by default. public class Cron {
private static class JobRegistry implements JobFactory {
private final Map<String, Job> jobByName = new HashMap<String, Job>();
public void register(String name, Job job) {
jobByName.put(name, job);
}
@Override
public Job newJob(TriggerFiredBundle bundle) throws SchedulerException {
return jobByName.get(bundle.getJobDetail().getName());
}
}
private final Scheduler quartz;
private final JobRegistry jobFactory = new JobRegistry();
private final AtomicInteger sequence = new AtomicInteger();
public Cron(SchedulerFactory schedulerFactory) throws SchedulerException {
quartz = schedulerFactory.getScheduler();
quartz.setJobFactory(jobFactory);
}
public void schedule(Job job, String expression) throws ParseException, SchedulerException {
int id = sequence.getAndIncrement();
jobFactory.register("job" + id, job);
JobDetail detail = new JobDetail("job" + id, job.getClass());
CronTrigger trigger = new CronTrigger("trigger" + id, null, expression);
quartz.scheduleJob(detail, trigger);
}
public void start() throws SchedulerException {
quartz.start();
}
public void shutdown() throws SchedulerException {
quartz.shutdown();
}
}
Pretty straightforward. Note that it’s not intended for use with clustering and a database, only with a RAMJobStore. Incidentally, if you’re using Quartz v1.7.3 or higher you may want to disable its new “update check” unwanted feature, or it will make a periodic web request to the Terracotta servers.
| |





