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.
| |