Dynamic Configuration of Quartz Scheduled Tasks in Spring Boot

This article demonstrates how to implement a dynamic, non‑blocking Quartz scheduling solution in a Spring Boot application, covering Maven dependencies, database schema, initialization steps, custom job factory, listener, and common Scheduler API operations such as pause, resume, delete, and trigger.

Top Architect
Top Architect
Top Architect
Dynamic Configuration of Quartz Scheduled Tasks in Spring Boot

The article introduces a dynamic configuration approach for Quartz scheduled tasks, addressing the drawbacks of static XML‑based scheduling that requires application restarts for changes.

Maven dependencies for Quartz and Spring context support are provided:

<!-- quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>

A MySQL task table ( sys_task) is defined to store job metadata such as name, description, cron expression, bean class, status, group, and audit fields.

CREATE TABLE `sys_task` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `job_name` varchar(255) DEFAULT NULL COMMENT '任务名',
  `description` varchar(255) DEFAULT NULL COMMENT '任务描述',
  `cron_expression` varchar(255) DEFAULT NULL COMMENT 'cron表达式',
  `bean_class` varchar(255) DEFAULT NULL COMMENT '任务执行时调用哪个类的方法 包名+类名',
  `job_status` varchar(255) DEFAULT NULL COMMENT '任务状态',
  `job_group` varchar(255) DEFAULT NULL COMMENT '任务分组',
  `create_user` varchar(64) DEFAULT NULL COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_user` varchar(64) DEFAULT NULL COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;

Implementation steps :

Start the Spring Boot project; the ScheduleJobInitListener (a CommandLineRunner) loads tasks.

Read enabled tasks from the database and add them to the Quartz Scheduler.

The scheduler automatically triggers the jobs based on their CronTrigger.

A custom JobFactory (extending AdaptableJobFactory) injects Spring beans into job instances.

Key code snippets :

Quartz configuration bean:

@Configuration
public class QuartzConfigration {
    @Autowired
    JobFactory jobFactory;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean bean = new SchedulerFactoryBean();
        bean.setOverwriteExistingJobs(true);
        bean.setQuartzProperties(quartzProperties());
        bean.setJobFactory(jobFactory);
        return bean;
    }

    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean pf = new PropertiesFactoryBean();
        pf.setLocation(new ClassPathResource("/config/quartz.properties"));
        pf.afterPropertiesSet();
        return pf.getObject();
    }

    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }
}

Listener that initializes tasks:

@Component
@Order(1)
public class ScheduleJobInitListener implements CommandLineRunner {
    @Autowired
    TaskService scheduleJobService;

    @Override
    public void run(String... args) throws Exception {
        try {
            scheduleJobService.initSchedule();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Adding a job to the scheduler:

public void addJob(TaskDO task) {
    try {
        Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(task.getBeanClass()).newInstance().getClass();
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
            .withIdentity(task.getJobName(), task.getJobGroup())
            .build();
        Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity(task.getJobName(), task.getJobGroup())
            .startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
            .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression()))
            .startNow()
            .build();
        scheduler.scheduleJob(jobDetail, trigger);
        if (!scheduler.isShutdown()) {
            scheduler.start();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Common Scheduler API examples (pause, resume, delete, trigger, update cron):

public void pauseJob(TaskDO task) throws SchedulerException {
    JobKey key = JobKey.jobKey(task.getJobName(), task.getJobGroup());
    scheduler.pauseJob(key);
}

public void resumeJob(TaskDO task) throws SchedulerException {
    JobKey key = JobKey.jobKey(task.getJobName(), task.getJobGroup());
    scheduler.resumeJob(key);
}

public void deleteJob(TaskDO task) throws SchedulerException {
    JobKey key = JobKey.jobKey(task.getJobName(), task.getJobGroup());
    scheduler.deleteJob(key);
}

public void runJobNow(TaskDO task) throws SchedulerException {
    JobKey key = JobKey.jobKey(task.getJobName(), task.getJobGroup());
    scheduler.triggerJob(key);
}

public void updateJobCron(TaskDO task) throws SchedulerException {
    TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup());
    CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
    CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCronExpression());
    trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
    scheduler.rescheduleJob(triggerKey, trigger);
}

The article concludes with a link to a live demo, source code repository, and Quartz documentation, inviting readers to try the implementation and explore additional API features.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaDynamic ConfigurationSpring BootQuartzScheduled Tasks
Top Architect
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.