This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Boot 3.3.5!

Quartz Scheduler

Spring Boot offers several conveniences for working with the Quartz scheduler, including the spring-boot-starter-quartz starter. If Quartz is available, a Scheduler is auto-configured (through the SchedulerFactoryBean abstraction).

Beans of the following types are automatically picked up and associated with the Scheduler:

  • JobDetail: defines a particular Job. JobDetail instances can be built with the JobBuilder API.

  • Calendar.

  • Trigger: defines when a particular job is triggered.

By default, an in-memory JobStore is used. However, it is possible to configure a JDBC-based store if a DataSource bean is available in your application and if the spring.quartz.job-store-type property is configured accordingly, as shown in the following example:

  • Properties

  • YAML

spring.quartz.job-store-type=jdbc
spring:
  quartz:
    job-store-type: "jdbc"

When the JDBC store is used, the schema can be initialized on startup, as shown in the following example:

  • Properties

  • YAML

spring.quartz.jdbc.initialize-schema=always
spring:
  quartz:
    jdbc:
      initialize-schema: "always"
By default, the database is detected and initialized by using the standard scripts provided with the Quartz library. These scripts drop existing tables, deleting all triggers on every restart. It is also possible to provide a custom script by setting the spring.quartz.jdbc.schema property.

To have Quartz use a DataSource other than the application’s main DataSource, declare a DataSource bean, annotating its @Bean method with @QuartzDataSource. Doing so ensures that the Quartz-specific DataSource is used by both the SchedulerFactoryBean and for schema initialization. Similarly, to have Quartz use a TransactionManager other than the application’s main TransactionManager declare a TransactionManager bean, annotating its @Bean method with @QuartzTransactionManager.

By default, jobs created by configuration will not overwrite already registered jobs that have been read from a persistent job store. To enable overwriting existing job definitions set the spring.quartz.overwrite-existing-jobs property.

Quartz Scheduler configuration can be customized using spring.quartz properties and SchedulerFactoryBeanCustomizer beans, which allow programmatic SchedulerFactoryBean customization. Advanced Quartz configuration properties can be customized using spring.quartz.properties.*.

In particular, an Executor bean is not associated with the scheduler as Quartz offers a way to configure the scheduler through spring.quartz.properties. If you need to customize the task executor, consider implementing SchedulerFactoryBeanCustomizer.

Jobs can define setters to inject data map properties. Regular beans can also be injected in a similar manner, as shown in the following example:

  • Java

  • Kotlin

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import org.springframework.scheduling.quartz.QuartzJobBean;

public class MySampleJob extends QuartzJobBean {

	// fields ...

	private MyService myService;

	private String name;


	// Inject "MyService" bean
	public void setMyService(MyService myService) {
		this.myService = myService;
	}

	// Inject the "name" job data property
	public void setName(String name) {
		this.name = name;
	}

	@Override
	protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
		this.myService.someMethod(context.getFireTime(), this.name);
	}

}
import org.quartz.JobExecutionContext
import org.springframework.scheduling.quartz.QuartzJobBean

class MySampleJob : QuartzJobBean() {

	// fields ...

	private var myService: MyService? = null

	private var name: String? = null

	// Inject "MyService" bean
	fun setMyService(myService: MyService?) {
		this.myService = myService
	}

	// Inject the "name" job data property
	fun setName(name: String?) {
		this.name = name
	}

	override fun executeInternal(context: JobExecutionContext) {
		myService!!.someMethod(context.fireTime, name)
	}

}