Implementing Scheduled Tasks with Quartz in Spring

Quartz Overview

Quartz is an open-source project specializing in job scheduling. It can be used standalone or integrated with the Spring framework, with the latter being the preferred approach in production environments. Quartz enables development of single or multiple scheduled tasks, each with configurable execution patterns such as hourly execution, monthly execution at specific times, or end-of-month execution.

Official website: http://www.quartz-scheduler.org/

Maven dependencies:

<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz</artifactId>
  <version>2.2.1</version>
</dependency>
<dependency>
  <groupId>org.quartz-scheduler</groupId>
  <artifactId>quartz-jobs</artifactId>
  <version>2.2.1</version>
</dependency>

Basic Quartz Integration Example

This example demonstrates integrating Quartz with Spring. The implementation steps are as follows:

Step 1: Create a Maven project and add Quartz and Spring dependencies

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>scheduler-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>
    </dependencies>
</project>

Step 2: Create a custom job class

package com.example.scheduler;

public class ScheduledTask {
    public void execute() {
        System.out.println("Scheduled task is running...");
    }
}

Step 3: Create Spring configuration file (scheduler-config.xml) to configure the job, job detail, trigger, and scheduler factory

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- Register custom job bean -->
    <bean id="scheduledTask" class="com.example.scheduler.ScheduledTask"></bean>
    
    <!-- Register JobDetail for reflection-based job invocation -->
    <bean id="taskJobDetail" 
          class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="scheduledTask"/>
        <property name="targetMethod" value="execute"/>
    </bean>
    
    <!-- Register trigger with cron expression -->
    <bean id="taskTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="taskJobDetail"/>
        <property name="cronExpression">
            <value>0/10 * * * * ?</value>
        </property>
    </bean>
    
    <!-- Register scheduler factory for task management -->
    <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="taskTrigger"/>
            </list>
        </property>
    </bean>
</beans>

Step 4: Create main class for testing

package com.example.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {
    public static void main(String[] args) {
        new ClassPathXmlApplicationContext("scheduler-config.xml");
    }
}

Running this application will display output every 10 seconds, confirming the scheduled task executes as configured.

Cron Expression Syntax

The expression 0/10 * * * * ? used above is a cron expression that precisely defines execution timing. Cron expressions consist of seven fields separated by spaces, with the last field (year) being optional. Each field has specific allowed values and special characters.

Special characters explained:

  • Comma (,): Specifies a list of values, e.g., 1,4,5,7 in the month field means January, April, May, and July

  • Hyphen (-): Specifies a range, e.g., 3-6 in the hour field means 3am through 6am

  • Asterisk (*): Includes all valid values for the field, e.g., * in month means every month

  • Slash (/): Specifies increments, e.g., 0/15 in seconds means every 15 seconds

  • Question mark (?): Used only in day-of-month and day-of-week fields, cannot be used in both simultaneously, indicates no specific value

  • Hash (#): Used only in day-of-week field to specify which week of the month, e.g., 6#3 means the third Friday of the month

  • L: Represents the last value, used only in day-of-month and day-of-week. In day-of-month, it means the last day of the specified month. In day-of-week, it means Saturday

  • W: Represents weekdays (Monday through Friday), used only in day-of-month, specifies the nearest weekday to the specified date

Online Cron Expression Generators

Writing cron expressions manulaly can be challenging. Online tools are available to generate expressions based on requirements:

http://cron.qqe2.com/

Practical Application: Scheduled Cleanup of Orphan Images

In a health management system, package information and images are submitted separately when adding new packages. Users upload images to cloud storage first, then submit additional information. If users upload images but never complete the submission process, those images become orphan files with no database records.

The solution involves scheduled cleanup of these orphan images. The approach uses Redis sets to track uploaded images: one set stores all uploaded images, another set stores images associated with saved database records. The difference between these sets identifies orphan images.

This section implements a Quartz-based scheduled task to identify and remove orphan images by calculating the Redis set difference.

Implementaiton steps:

  1. Create a Maven project with war packaging, add Quartz and related dependencies

  2. Create the orphan image cleanup job class

package com.example.jobs;

import com.example.constant.RedisKeys;
import com.example.util.CloudStorageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.JedisPool;
import java.util.Set;

public class OrphanImageCleanupJob {
    @Autowired
    private JedisPool jedisPool;
    
    public void cleanupOrphanImages() {
        Set<String> orphanImages = 
            jedisPool.getResource().sdiff(RedisKeys.UPLOADED_IMAGES, 
                                          RedisKeys.PERSISTED_IMAGES);
        if (orphanImages != null) {
            for (String imageName : orphanImages) {
                CloudStorageUtil.removeFile(imageName);
                jedisPool.getResource().srem(RedisKeys.UPLOADED_IMAGES, imageName);
            }
        }
    }
}

The job compares the two Redis sets, identifies images that exist in the uploaded set but not in the persisted set, removes them from the cloud storage, and updates the Redis tracking sets accordingly.

Tags: Quartz Spring Scheduled Tasks Cron Expression java

Posted on Fri, 08 May 2026 03:41:56 +0000 by KoshNaranek