Planifier des taches avec Spring Boot et Quartz Scheduler

Publié le 21/01/2026 Source : sfeir.dev

Dans les applications modernes, la gestion de tâches planifiées est une nécessité : génération de rapports quotidiens, suppression de données obsolètes, envoi de notifications régulières, etc.
Spring Boot fournit une annotation simple @Scheduled, mais lorsque les besoins deviennent plus complexes (persistance des tâches, clustering, exécutions dynamiques), Quartz Scheduler s’impose comme une solution robuste et éprouvée.

Dans cet article, nous allons explorer comment intégrer Quartz à un projet Spring Boot, configurer un scheduler persistant, et mettre en place un exemple concret de suppression d’utilisateurs inactifs.

Installation

Pour ajouter Quart Scheduler à votre projet, rien de plus simple, il faut ajouter la dépendance suivante dans votre pom.xml :

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

Configuration de Quartz

Spring Boot configure Quartz automatiquement via QuartzAutoConfiguration.
Cependant, pour un contrôle plus fin, il est utile de préciser le type de stockage dans application.properties

spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=always

Exemple pratique : suppression des utilisateurs inactifs

Le job Quartz

@Component
public class InactiveUserCleanupJob implements Job {

    private final UserService userService;

    public InactiveUserCleanupJob(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void execute(JobExecutionContext context) {
        userService.deleteInactiveUsers();
    }
}

La configuration du job et du trigger

@Configuration
public class JobSchedulerConfig {

    @Bean
    public JobDetail inactiveUserJobDetail() {
        return JobBuilder.newJob(InactiveUserCleanupJob.class)
                .withIdentity("inactiveUserJob")
                .storeDurably()
                .build();
    }

    @Bean
    public Trigger inactiveUserJobTrigger(JobDetail jobDetail) {
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail)
                .withIdentity("inactiveUserTrigger")
                .withSchedule(CronScheduleBuilder.dailyAtHourAndMinute(13, 0))
                .build();
    }
}

La configuration de l’usine de jobs Quartz

Quartz, par défaut, ne connaît pas Spring et ne sait pas injecter les beans.
Nous configurons donc une JobFactory qui délègue la création des jobs à Spring.

@Configuration
public class QuartzJobFactoryConfig {

    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }
}

Et l’implémentation personnalisée :

public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    private transient AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

La logique métier

@Service
public class UserService {

    private static final Logger LOG = LoggerFactory.getLogger(UserService.class);

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional
    public void deleteInactiveUsers() {
        int deleted = userRepository.deleteByStatus("inactive");
        LOG.info("Suppression de {} utilisateurs inactifs.", deleted);
    }
}

Gestion dynamique des tâches

Spring Boot facilite grandement le suivi et la gestion de Quartz grâce aux Actuators, un endpoint dédié quartz est disponible, permettant d’inspecter et d’interagir avec les jobs Quartz directement via HTTP.

Configuration des Actuators

Pour activer l’endpoint quartz, il faut l’ajouter explicitement dans les propriétés de configuration :

management.endpoints.web.exposure.include=quartz
management.endpoint.quartz.enabled=true

Exemples de requêtes

Reprenons notre job de suppression des users inactifs inactiveUserJob

Lister les jobs

curl http://localhost:8080/actuator/quartz/jobs

Réponse :

{
  "groups": {
    "DEFAULT": {
      "jobs": [
        "inactiveUserJob"
      ]
    }
  }
}

Détails d’un job

Pour obtenir les détails du job InactiveUserJob appartenant au groupe DEFAULT :

curl http://localhost:8080/actuator/quartz/jobs/DEFAULT/inactiveUserJob

Réponse :

{
  "data": {

  },
  "triggers": [
    {
      "group": "DEFAULT",
      "name": "inactiveUserTrigger",
      "nextFireTime": "2025-08-19T11:00:00.000+00:00",
      "priority": 5
    }
  ],
  "group": "DEFAULT",
  "name": "inactiveUserJob",
  "description": "Suppression des users inactifs",
  "className": "fr.eletutour.quartz.tutorial.job.InactiveUserCleanupJob",
  "durable": true,
  "requestRecovery": false
}

Déclencher manuellement un job

il est également possible de déclencher manuellement un job Quartz via Actuator :

POSt http://localhost:8080/actuator/quartz/jobs/DEFAULT/inactiveUserJob

{
    "state": "running"
}

ce qui donnera la réponse suivante

{
    "group": "DEFAULT",
    "name": "inactiveUserJob",
    "className": "fr.eletutour.quartz.tutorial.job.InactiveUserCleanupJob",
    "triggerTime": "2025-08-18T17:47:34.057570Z"
}

Quartz Scheduler vs Spring Batch

Dans un précédent article, nous avions vu comment planifier des tâches en utilisant Spring Batch

Planifier des tâches avec Spring Batch

Bien que Quartz et Spring Batch soient deux briques de l’écosystème Spring, leurs objectifs diffèrent.

Caractéristique Quartz Scheduler Spring Batch
Objectif principal Planifier et exécuter des tâches récurrentes ou ponctuelles. Traiter de grands volumes de données en lots (batch processing).
Gestion du temps Exécution basée sur le temps (cron, intervalle, calendrier). Exécution déclenchée à la demande, souvent par un planificateur externe (Quartz, cron Linux, etc.).
Exemple typique Envoi quotidien d’emails, purge de données obsolètes, rappels planifiés. Migration de données, génération de rapports volumineux, calculs massifs.
Persistance Stocke l’état des jobs et triggers dans une base de données. Stocke l’état des exécutions de batchs (métadonnées, état des steps, reprise après erreur).
Scalabilité Support du clustering natif (plusieurs nœuds peuvent exécuter des tâches). Support du partitionnement et du parallélisme pour traiter de gros volumes.
Simplicité d’usage Très adapté pour la planification flexible et dynamique. Plus complexe, mais idéal pour orchestrer des traitements longs et critiques.

🔎 On peut retenir que :

Dans un projet réel, il n’est pas rare de combiner les deux : Quartz planifie, et Spring Batch exécute le traitement.

Conclusion

Quartz Scheduler, couplé à Spring Boot, offre une solution robuste pour la gestion avancée des tâches planifiées.
Il convient particulièrement lorsque :

Pour des besoins plus simples, @Scheduled ou TaskExecutor peuvent suffire.
Pour du traitement de masse, Spring Batch est le choix adapté, éventuellement orchestré par Quartz.


Tout le code relatif à cet article est trouvable ici, si vous souhaitez approfondir le sujet et faire des tests