Course – RWSB – NPI (cat=REST/Spring/Spring Boot)
announcement - icon

Now that the new version of REST With Spring - “REST With Spring Boot” is finally out, the current price will be available until the 22nd of June, after which it will permanently increase by 50$


1. Overview

In this tutorial, we’ll build a simple Scheduler in Spring with Quartz.

We’ll begin with a simple goal in mind, to easily configure a new scheduled job.

1.1. Key Components of the Quartz API

Quartz has a modular architecture. It consists of several basic components that we can combine as required. In this tutorial, we’ll focus on the ones that are common to every job: Job, JobDetail, Trigger and Scheduler.

Although we’ll use Spring to manage the application, each individual component can be configured in two ways: the Quartz way or the Spring way (using its convenience classes).

We’ll cover both options as far as possible, for the sake of completeness, but we may adopt either. Now let’s start building, one component at a time.

Further reading:

A Guide to the Spring Task Scheduler

A quick and practical guide to scheduling in Spring with Task Scheduler

Scheduling in Jakarta EE

A demonstration of how to schedule tasks in Jakarta EE using the @Schedule annotation and the timer service.

Introduction to Drools

Learn how to use Drools as a Business Rule Management System (BRMS).

2. Job and JobDetail

2.1. Job

The API provides a Job interface that has just one method, execute. It must be implemented by the class that contains the actual work to be done, i.e. the task. When a job’s trigger fires, the scheduler invokes the execute method, passing it a JobExecutionContext object.

The JobExecutionContext provides the job instance with information about its runtime environment, including a handle to the scheduler, a handle to the trigger, and the job’s JobDetail object.

In this quick example, the job delegates the task to a service class:

public class SampleJob implements Job {

    private SampleJobService jobService;

    public void execute(JobExecutionContext context) throws JobExecutionException {

2.2. JobDetail

While the job is the workhorse, Quartz doesn’t store an actual instance of the job class. Instead, we can define an instance of the Job using the JobDetail class. The job’s class must be provided to the JobDetail, so that it knows the type of the job to be executed.

2.3. Quartz JobBuilder

The Quartz JobBuilder provides a builder-style API for constructing JobDetail entities:

public JobDetail jobDetail() {
    return JobBuilder.newJob().ofType(SampleJob.class)
      .withDescription("Invoke Sample Job service...")

2.4. Spring JobDetailFactoryBean

Spring’s JobDetailFactoryBean provides bean-style usage for configuring JobDetail instances. It uses the Spring bean name as the job name, if not otherwise specified:

public JobDetailFactoryBean jobDetail() {
    JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
    jobDetailFactory.setDescription("Invoke Sample Job service...");
    return jobDetailFactory;

Every execution of the job creates a new instance of JobDetail. The JobDetail object conveys the detailed properties of the job. Once the execution is complete, references to the instance are dropped.

3. Trigger

A Trigger is the mechanism to schedule a Job, i.e. a Trigger instance “fires” the execution of a job. There’s a clear separation of responsibilities between the Job (notion of task) and Trigger (scheduling mechanism).

In addition to a Job, the trigger also needs a type, which we can choose based on the scheduling requirements.

Let’s say we want to schedule our task to execute once every hour indefinitely, then we can use Quartz’s TriggerBuilder or Spring’s SimpleTriggerFactoryBean to do so.

3.1. Quartz TriggerBuilder

TriggerBuilder is a builder-style API for constructing the Trigger entity:

public Trigger trigger(JobDetail job) {
    return TriggerBuilder.newTrigger().forJob(job)
      .withDescription("Sample trigger")

3.2. Spring SimpleTriggerFactoryBean

SimpleTriggerFactoryBean provides bean-style usage for configuring SimpleTrigger. It uses the Spring bean name as the trigger name, and defaults to indefinite repetition if not otherwise specified:

public SimpleTriggerFactoryBean trigger(JobDetail job) {
    SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
    return trigger;

4. Configuring the JobStore

JobStore provides the storage mechanism for the Job and Trigger. It’s also responsible for maintaining all the data relevant to the job scheduler. The API supports both in-memory and persistent stores.

4.1. In-Memory JobStore

For our example, we’ll use the in-memory RAMJobStore, which offers blazing-fast performance and simple configuration via


The obvious drawback of the RAMJobStore is that it’s volatile in nature. All the scheduling information is lost between shutdowns. If we need to keep job definitions and schedules between shutdowns, we can use the persistent JDBCJobStore instead.

To enable an in-memory JobStore in Spring, we’ll set this property in our


4.2. JDBC JobStore

There are two types of JDBCJobStore: JobStoreTX and JobStoreCMT. They both do the same job of storing scheduling information in a database.

The difference between the two is how they manage the transactions that commit the data. The JobStoreCMT type requires an application transaction to store data, whereas the JobStoreTX type starts and manages its own transactions.

There are several properties to set for a JDBCJobStore. At a minimum, we must specify the type of JDBCJobStore, the data source, and the database driver class. There are driver classes for most databases, but StdJDBCDelegate covers most cases:


Setting up a JDBC JobStore in Spring takes a few steps. First, we’ll set the store type in our


Then we’ll need to enable auto-configuration and give Spring the data source needed by the Quartz scheduler. The @QuartzDataSource annotation does the hard work in configuring and initializing the Quartz database for us:

public class SpringQrtzScheduler {

    public DataSource quartzDataSource() {
        return DataSourceBuilder.create().build();

5. Scheduler

The Scheduler interface is the main API for interfacing with the job scheduler.

A Scheduler can be instantiated with a SchedulerFactory. Once created, we can register Jobs and Triggers with it. Initially, the Scheduler is in “stand-by” mode, and we must invoke its start method to start the threads that fire the execution of jobs.

5.1. Quartz StdSchedulerFactory

By simply invoking the getScheduler method on the StdSchedulerFactory, we can instantiate the Scheduler, initialize it (with the configured JobStore and ThreadPool), and return a handle to its API:

public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory) 
  throws SchedulerException {
    Scheduler scheduler = factory.getScheduler();
    scheduler.scheduleJob(job, trigger);
    return scheduler;

5.2. Spring SchedulerFactoryBean

Spring’s SchedulerFactoryBean provides bean-style usage for configuring a Scheduler, managing its life-cycle within the application context, and exposing the Scheduler as a bean for dependency injection:

public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
    SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
    schedulerFactory.setConfigLocation(new ClassPathResource(""));

    return schedulerFactory;

5.3. Configuring SpringBeanJobFactory

The SpringBeanJobFactory provides support for injecting the scheduler context, job data map, and trigger data entries as properties into the job bean while creating an instance.

However, it lacks support for injecting bean references from the application context. Thanks to the author of this blog post, we can add auto-wiring support to SpringBeanJobFactory: 

public SpringBeanJobFactory springBeanJobFactory() {
    AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
    return jobFactory;

6. Conclusion

In this article, we built our first basic scheduler using the Quartz API, as well as Spring’s convenience classes.

The key takeaway is that we’re able to configure a job with just a few lines of code, without using any XML-based configuration.

The complete source code for the example is available in this github project. This is a Maven project, so we can import it and run it as-is. The default setting uses Spring’s convenience classes, but we can easily switch it to Quartz API with a run-time parameter (refer to the in the repository).

Course – RWSB – NPI (cat=REST/Spring/Spring Boot)
announcement - icon

Now that the new version of REST With Spring - “REST With Spring Boot” is finally out, the current price will be available until the 22nd of June, after which it will permanently increase by 50$


Course – LS (cat=Spring)
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:


res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.