Quartz fits
whenever you have any need for cron-like functionality within your java application, Quartz is the obvious chose for quite a long time now.
i did not need much of what quartz had to offer, so i went with a home-grown implementation. why? the fear of having to integrate a good, but feature-rich framework, you really don’t need most of the time.
well, that was a mistake. Quartz offers a very easy and stable API and a bunch of good helper classes, designed after common usecases. but there is one more important quality that every good framework nowadays has to have: it is non-intrusive in regards to creating its objects.
my ‘special’ case was integration with guice, so that i could use @Inject to implement my jobs. i was pleased to learn that it was as easy as this:
| Java | | copy | | ? |
final class GuiceJobFactory implements JobFactory |
{ |
private final Injector guice; |
@Inject |
public GuiceJobFactory(final Injector guice) |
{ |
this.guice = guice; |
} |
@Override |
public Job newJob(final TriggerFiredBundle bundle) throws SchedulerException |
{ |
JobDetail jobDetail = bundle.getJobDetail(); |
Class jobClass = jobDetail.getJobClass(); |
return (Job) guice.getInstance(jobClass); |
} |
} |
this example class is used to delegate the actual object creation to Guice. this makes Quartz integration a no-brainer, whatever environment you need it in.
all you have to do then is create the Scheduler accordingly:
| Java | | copy | | ? |
public class Quartz |
{ |
private final Scheduler scheduler; |
@Inject |
public Quartz(final SchedulerFactory factory, final GuiceJobFactory jobFactory) throws SchedulerException |
{ |
scheduler = factory.getScheduler(); |
scheduler.setJobFactory(jobFactory); |
scheduler.start(); |
} |
public final Scheduler getScheduler() |
{ |
return scheduler; |
} |
public void shutdown() |
{ |
try |
{ |
scheduler.shutdown(); |
} |
catch (SchedulerException e) |
{ |
// ... handle it |
} |
} |
} |
} |
and bind it all together like:
| Java | | copy | | ? |
public class QuartzModule extends AbstractModule |
{ |
@Override |
protected void configure() |
{ |
bind(SchedulerFactory.class).to(StdSchedulerFactory.class).in(Scopes.SINGLETON); |
bind(GuiceJobFactory.class).in(Scopes.SINGLETON); |
bind(Quartz.class).in(Scopes.SINGLETON); |
} |
} |
what did i learn from that?
frameworks are easy to integrate as long as they do not necessarily claim to manage the lifecycle of (even their own) objects unless absolutely necessary.
want another proof? see Wicket: Application.newSession(…)
Update: Trivial example of how to use Guice to schedule a Job as requested by Bo in comments.
| Java | | copy | | ? |
public class Main |
{ |
public static void main(final String[] args) |
{ |
final Injector i = Guice.createInjector(new QuartzModule(), new AbstractModule() |
{ |
@Override |
protected void configure() |
{ |
bind(FooJobActivator.class).asEagerSingleton(); |
} |
}); |
System.out.println("Guice ready, waiting 130 secs now..."); |
VMHelper.sleepSeconds(130); |
System.out.println("shutdown"); |
i.getInstance(Quartz.class).shutdown(); |
System.out.println("done"); |
} |
static class FooJob implements Job |
{ |
public FooJob() |
{ |
System.out.println(this + " was created"); |
} |
@Override |
public void execute(final JobExecutionContext arg0) throws JobExecutionException |
{ |
System.out.println(this + " was run!"); |
} |
} |
static class FooJobActivator |
{ |
@Inject |
public FooJobActivator(final Quartz q) throws SchedulerException |
{ |
q.getScheduler().scheduleJob(new JobDetail("myFooJob", null, FooJob.class), |
TriggerUtils.makeMinutelyTrigger("MIN_TRIGGER")); |
} |
} |
} |


Ok, you convinced me to not roll out my own. I’ve used Quartz with success in the past, but every time I go through the API, I also think, hmmm, I would’ve done it like this and that… (arrogant, isn’t it!). But you’re right, Quartz is stable and does the job well, and hey even integration with Guice is a piece of cake, so no excuses
*g* glad to hear that. i agree that the API does not feel right in every corner, but it does the job. there certainly are more entertaining things out there than creating yet-another-cron-in-java.
Hi Uwe,
I’m very new to Guice so can you please answer this (I did faithfully wired parts according to your example):
1. It’s not obvious how to set-up the scheduler. Where and how would I wire the Trigger (I can use Trigger#makeMinutelyTrigger)?
2. I really have just one type of job I will be executing, I understand that details in the JobFactory#newJob are coming from the TriggerFiredBundle parameter but where/how do I wire that? And where/how do I create or wire concrete Job?
I have a post on StackOverflow.com that references your excellent article – http://bit.ly/auBM3k
Thanks,
Bo Stone
Hi Bo, please see updated article. you´d want to schedule a JobDetail together with a trigger. In the example i used an Activator to do this at wiring time.
output should be something like:
Guice ready, waiting 130 secs now…
Main$FooJob@2a5330 was created
Main$FooJob@2a5330 was run!
Main$FooJob@10655dd was created
Main$FooJob@10655dd was run!
Main$FooJob@ef5502 was created
Main$FooJob@ef5502 was run!
shutdown
done
You see one creation and execution of FooJob each at now, now+1m and now+2m.
Uwe – thank you again! You really saved the day for me
You´re welcome.
How can I shutdown Quartz in GuiceContextListener in contextDestroyed() method?
the example above belongs to an outdated api, but i guess the current way would be:
http://www.quartz-scheduler.org/docs/api/1.8.1/org/quartz/Scheduler.html#shutdown(boolean)