Mastering Quartz Scheduler in Spring Boot: From Basics to Advanced Integration
This article provides a comprehensive guide to integrating the Quartz job‑scheduling library with Spring Boot, covering core concepts, Maven setup, job and trigger definitions, concurrency control, dynamic task creation via REST, and initialization strategies, all illustrated with complete Java code examples and diagrams.
Introduction
The project required a flexible way for customers to define task start times, which led to the adoption of Quartz, an open‑source Java scheduler offering persistent jobs, trigger management, and more advanced features than java.util.Timer.
Core Concepts
Quartz revolves around three main components:
Job : a class implementing org.quartz.Job with an execute() method.
Trigger : defines when a job runs; common types are SimpleTrigger and CronTrigger.
Scheduler : orchestrates triggers and jobs.
Basic Usage
Add the Quartz dependencies to a Maven project:
<!-- core package -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!-- utility package -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>Define a job class:
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Task executed...");
}
}Schedule the job in a main method:
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("job1", "group1")
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(30)
.repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
TimeUnit.MINUTES.sleep(1);
scheduler.shutdown();JobDetail and Trigger Details
When the scheduler fires a job, it creates a fresh instance of the Job class, executes execute(), and then discards the instance, preventing concurrency issues. The JobDetail holds metadata and a JobDataMap for parameters.
Concurrency Control
Quartz provides two annotations: @DisallowConcurrentExecution – prevents multiple instances of the same JobDetail from running simultaneously. @PersistJobDataAfterExecution – saves changes made to the JobDataMap after execution.
SimpleTrigger
Used for straightforward schedules, e.g., run once at a specific time or repeat at a fixed interval. Example with repeat count:
TriggerBuilder.newTrigger()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(30)
.withRepeatCount(5))
.build();CronTrigger
Supports calendar‑based expressions. A typical cron expression is "* * * * * ?". The article includes a reference image for the expression syntax.
Spring Boot Integration
Add the starter dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>Configure the scheduler bean with properties such as thread pool size, job store class, clustering, and misfire policies:
@Configuration
public class ScheduleConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "shivaScheduler");
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
prop.put("org.quartz.jobStore.isClustered", "true");
// additional properties omitted for brevity
factory.setQuartzProperties(prop);
factory.setStartupDelay(1);
factory.setOverwriteExistingJobs(true);
return factory;
}
}Utility Classes
ScheduleUtilsbuilds job keys, trigger keys, and creates or updates jobs in the scheduler. It also handles misfire policies via CronScheduleBuilder. AbstractQuartzJob implements Job and defines before(), after(), and an abstract doExecute() method that concrete jobs override. JobInvokeUtil uses reflection to invoke the target method defined in the invokeTarget string, supporting bean lookup, static class instantiation, and parameter conversion for strings, booleans, longs, and doubles.
Dynamic Task Management
Tasks can be added via a JSON payload (example shown) that specifies fields such as cronExpression, invokeTarget, concurrent, and status. The service inserts the task into the database with a paused status, then calls ScheduleUtils.createScheduleJob() to register it.
Starting or pausing a task updates the database and calls scheduler.resumeJob() or scheduler.pauseJob() accordingly.
Initialization on Application Startup
A @PostConstruct method clears the scheduler, loads all jobs from the database, and recreates them, ensuring the in‑memory schedule matches persisted data.
Other Notes
Concurrency can be controlled with @DisallowConcurrentExecution. Without it, Quartz may start a new thread even if the previous execution is still running.
Specific dates can be excluded using a Calendar added to the scheduler and referenced by triggers via modifiedByCalendar().
https://gitee.com/qianwei4712/code-of-shiva/tree/master/quartz
Overall, the article walks through the complete lifecycle of Quartz integration: dependency setup, job/trigger definition, Spring Boot configuration, utility code for flexible execution, and runtime management of scheduled tasks.
Senior Brother's Insights
A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
