What is SchedulingConfigurer and when would you use it instead of the @Scheduled annotation?
answer
- @Scheduled is static, SchedulingConfigurer is programmatic
- one method: configureTasks(ScheduledTaskRegistrar)
- still needs @EnableScheduling
- addTriggerTask for dynamic next-run
- setScheduler to escape single default thread
basics
~20 sSchedulingConfigurer is an interface you implement on a @Configuration class to register scheduled tasks in code via a ScheduledTaskRegistrar, instead of the static @Scheduled annotation. Use it when the schedule must be computed at runtime.
solid answer
~30 s@Scheduled is fully static: its cron/fixedRate/fixedDelay are fixed at compile time (or bound once from properties). When the schedule itself has to be decided at runtime — read from a database, changed by an admin, or computed dynamically — you implement SchedulingConfigurer. It has one callback, configureTasks(ScheduledTaskRegistrar), where you register tasks programmatically: fixed-rate, fixed-delay, cron, or the powerful addTriggerTask(Runnable, Trigger) form that recomputes the next run time after every execution. You also use SchedulingConfigurer to supply your own TaskScheduler (thread pool) so scheduled work doesn't run on the single default thread. It requires @EnableScheduling somewhere in the context, just like @Scheduled.
code
java · 15 lines@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// give tasks a real pool instead of the single default thread
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(4));
// a plain fixed-rate task registered in code
taskRegistrar.addFixedRateTask(
() -> System.out.println("tick"),
Duration.ofSeconds(30));
}
}go deeper
Know it's the code-based alternative to @Scheduled and still needs @EnableScheduling.
Know the registrar methods (addTriggerTask, addCronTask, setScheduler) and that configureTasks runs once at startup.
Explain the single-thread default scheduler pitfall and why addTriggerTask enables dynamic scheduling.
Discuss coexistence with @Scheduled, shared TaskScheduler, and lifecycle ordering of the bean post-processor.
## The problem it solves Spring's `@Scheduled` annotation is **static**. Its attributes (`cron`, `fixedRate`, `fixedDelay`, `initialDelay`) are resolved once at startup — either as literals or from properties/SpEL. You cannot change them while the app is running, and you cannot compute the next execution based on runtime state (e.g. "run again in N minutes where N comes from the database"). `SchedulingConfigurer` is the escape hatch for **programmatic** task registration. ## Mechanics `SchedulingConfigurer` is a functional-style interface with a single method: ```java void configureTasks(ScheduledTaskRegistrar taskRegistrar); ``` You implement it on a `@Configuration` class. Spring's scheduling infrastructure (activated by `@EnableScheduling`) calls `configureTasks` during context initialization, handing you a `ScheduledTaskRegistrar`. On that registrar you register any number of tasks: - `addFixedRateTask(...)` / `addFixedDelayTask(...)` — the programmatic equivalents of `@Scheduled(fixedRate=...)`. - `addCronTask(...)` — programmatic cron. - `addTriggerTask(Runnable, Trigger)` — the most flexible form; the `Trigger` recomputes the next run **after each execution**, enabling truly dynamic schedules. - `setScheduler(...)` — supply your own `TaskScheduler` / `Executor` so tasks run on a real thread pool instead of the single-threaded default. ## Relationship to @EnableScheduling `@EnableScheduling` imports `ScheduledAnnotationBeanPostProcessor`, which both scans for `@Scheduled` methods **and** invokes every `SchedulingConfigurer` bean's `configureTasks`. So both mechanisms coexist in the same application and share the same `TaskScheduler`. ## When to use - Schedule value comes from a DB row, config service, or admin UI. - Next run time depends on the outcome/timing of the previous run. - You need explicit control over the scheduler thread pool. - You want to register a variable number of tasks discovered at runtime. ## Gotchas - Forgetting `@EnableScheduling` — then `configureTasks` is never called. - The default `TaskScheduler` (when you don't set one) is a **single-threaded** `ThreadPoolTaskScheduler`; long tasks block each other. Always call `taskRegistrar.setScheduler(...)` for concurrent workloads. - `configureTasks` runs **once at startup**. It is not a hook that re-fires when data changes — to change a schedule live you use a `Trigger` (which recomputes each cycle) or cancel and re-register a task.
- Does using SchedulingConfigurer remove the need for @EnableScheduling?No. @EnableScheduling activates the ScheduledAnnotationBeanPostProcessor that actually calls configureTasks. Without it, your SchedulingConfigurer bean is created but never invoked.
- Is configureTasks called repeatedly, so you can re-read the schedule?No, it runs once at context initialization. For a schedule that changes at runtime you register a Trigger (recomputed each cycle) or cancel and re-add tasks; configureTasks itself is not a polling hook.