Comprehensive Guide to Using Quartz Scheduler in Java with Spring Boot
This article provides a detailed tutorial on Quartz, a powerful Java scheduling framework, covering its core concepts, basic usage with SimpleTrigger and CronTrigger, advanced features such as multiple triggers, bean injection, and persistence, and includes complete Spring Boot code examples.
1. Introduction to Quartz
Quartz is a mature Java library for scheduling jobs without distributed requirements, offering dynamic management like start, pause, resume, and trigger time modification. It consists of three main components: Job, Trigger, and Scheduler.
2. Basic Usage
2.1 Interval‑Based Task
Use SimpleTrigger to run a job every few seconds. Example code adds the spring-boot-starter-quartz dependency, defines a SimpleJob implementing Job , creates a JobDetail and a Trigger with a 2‑second interval, schedules it, starts the scheduler, sleeps for 30 seconds, then shuts down.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
public class SimpleJob implements Job {
@Override
public void execute(JobExecutionContext ctx) {
System.out.println(Thread.currentThread().getName() + "--" +
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
.format(java.time.LocalDateTime.now()));
}
}
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
JobDetail job = JobBuilder.newJob(SimpleJob.class)
.withIdentity("job1", "group1").build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger-1", "trigger-group")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever())
.build();
scheduler.scheduleJob(job, trigger);
scheduler.start();
java.util.concurrent.TimeUnit.SECONDS.sleep(30);
scheduler.shutdown();2.2 Cron‑Expression Task
Define a CronTrigger with a cron expression. The same job class is used, but the trigger is built with CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 *") . The scheduler is started and run for 30 seconds before shutdown.
Trigger cronTrigger = TriggerBuilder.newTrigger()
.withIdentity("trigger-1", "trigger-group")
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 *"))
.build();3. Core Components Explained
3.1 Job
A Job is an interface with a single execute() method. Implementations are wrapped into a JobDetail via JobBuilder . Each JobDetail is uniquely identified by name and group.
3.2 Trigger
Four trigger types exist: SimpleTrigger , CronTrigger , CalendarIntervalTrigger , and DailyTimeIntervalTrigger . Triggers have states (NONE, NORMAL, PAUSED, COMPLETE, ERROR, BLOCKED) that affect execution.
3.3 Scheduler
The scheduler, created by StdSchedulerFactory , is the orchestrator. It provides APIs to start, shutdown, add jobs, pause/resume jobs or triggers, and query job/trigger details.
4. Advanced Usage
4.1 Multiple Triggers for One Job
Mark a JobDetail as durable with storeDurably() , add it to the scheduler without a trigger, then create several triggers that reference the same job via forJob(jobDetail) . Schedule each trigger separately.
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class)
.withIdentity("job1", "job-group")
.storeDurably()
.build();
Trigger trigger1 = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "trigger-group")
.startNow()
.forJob(jobDetail)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2).repeatForever())
.build();
Trigger trigger2 = TriggerBuilder.newTrigger()
.withIdentity("trigger2", "trigger-group")
.startNow()
.forJob(jobDetail)
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(3).repeatForever())
.build();
scheduler.addJob(jobDetail, false);
scheduler.scheduleJob(trigger1);
scheduler.scheduleJob(trigger2);4.2 Injecting Beans into Jobs
Two approaches: (1) Put required beans into the JobDataMap of the JobDetail ; (2) Use a static utility implementing ApplicationContextAware to fetch beans from the Spring context at runtime. The second method avoids serialization issues with non‑serializable beans.
@Component
public class SpringContextJobUtil implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext ctx) { this.context = ctx; }
public static Object getBean(String name) { return context.getBean(name); }
}
// In job execution
PersonMapper mapper = (PersonMapper) SpringContextJobUtil.getBean("personMapper");
List
list = mapper.queryList();4.3 Persistence (JDBCJobStore)
Quartz can store jobs and triggers in a database using JDBCJobStore . Add a connection‑pool dependency (e.g., c3p0), configure quartz.properties with datasource settings, create the required tables (provided by Quartz), and set org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX . This ensures tasks survive application restarts.
# quartz.properties excerpt
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=10
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.dataSource=qzDS
org.quartz.dataSource.qzDS.driver=com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL=jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8
org.quartz.dataSource.qzDS.user=root
org.quartz.dataSource.qzDS.password=rootAfter configuring, Quartz will persist job definitions, trigger states, and execution history in the database tables prefixed with QRTZ_ .
Conclusion
The guide covers everything from basic job scheduling to advanced scenarios like multiple triggers, Spring bean injection, and durable persistence, providing ready‑to‑run code snippets and configuration files for developers to integrate Quartz into Spring Boot projects.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.