Close

Spring - Customized @Scheduled annotation processing by extending ScheduledAnnotationBeanPostProcessor

[Last Updated: Oct 30, 2025]

ScheduledAnnotationBeanPostProcessor is responsible for detecting @Scheduled methods and registering them with a TaskScheduler. This BeanPostProcessor is automatically registered when we use @EnableScheduling on Spring's configuration class.

Following example shows how we can customize the behavior of ScheduledAnnotationBeanPostProcessor. We are going to do that by extending it.

Example

The Processor

This extension of ScheduledAnnotationBeanPostProcessor just do some logging, but it can be used for customization like dynamic scheduling based on runtime conditions, environment-specific scheduling, performance monitoring, conditionally enable or disable tasks etc.

package com.logicbig.example;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor;

import java.lang.reflect.Method;

public class CustomScheduledBeanPostProcessor extends ScheduledAnnotationBeanPostProcessor {

  @Override
  protected Runnable createRunnable(Object target, Method method, String qualifier) {
      //do some customizing if required
      Runnable runnable = super.createRunnable(target, method, qualifier);
      return () -> {
          System.out.printf("Running method %s.%s%n",
                  target.getClass().getSimpleName(), method.getName());
          runnable.run();
          System.out.printf("Finished running method %s.%s%n",
                  target.getClass().getSimpleName(), method.getName());
          System.out.println("-------");
      };
  }

  @Override
  protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
      System.out.printf("Processing @Scheduled method: %s.%s, scheduled Type: %s%n",
              method.getDeclaringClass().getSimpleName(), method.getName(), scheduled);
      super.processScheduled(scheduled, method, bean);
  }
}

The bean using @Scheduled annotations

package com.logicbig.example;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalTime;

@Component
public class MyBean {

  @Scheduled(fixedDelay = 1000)
  public void runTask() {
      System.out.printf("task thread: %s, time: %s%n",
              Thread.currentThread().getName(),
              LocalTime.now());
  }

  @Scheduled(fixedRate = 2000)
  public void runTask2() {
      System.out.printf("task 2 thread: %s, time: %s%n",
              Thread.currentThread().getName(),
              LocalTime.now());
  }
}

Main class

package com.logicbig.example;

import org.springframework.context.annotation.*;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@ComponentScan
@Configuration
public class ScheduledCustomizedProcessorExample {

  @Bean
  @Primary
  public static CustomScheduledBeanPostProcessor customScheduledBeanPostProcessor() {
      return new CustomScheduledBeanPostProcessor();
  }

  public static void main(String[] args) {
      AnnotationConfigApplicationContext context =
              new AnnotationConfigApplicationContext(
                      ScheduledCustomizedProcessorExample.class);

  }
}

Output

Processing @Scheduled method: MyBean.runTask2, scheduled Type: @org.springframework.scheduling.annotation.Scheduled(scheduler="", cron="", fixedRateString="", zone="", fixedDelay=-1L, fixedRate=2000L, initialDelayString="", initialDelay=-1L, timeUnit=MILLISECONDS, fixedDelayString="")
Processing @Scheduled method: MyBean.runTask, scheduled Type: @org.springframework.scheduling.annotation.Scheduled(scheduler="", cron="", fixedRateString="", zone="", fixedDelay=1000L, fixedRate=-1L, initialDelayString="", initialDelay=-1L, timeUnit=MILLISECONDS, fixedDelayString="")
Running method MyBean.runTask2
task 2 thread: pool-2-thread-1, time: 13:58:05.597719300
Finished running method MyBean.runTask2
-------
Running method MyBean.runTask
task thread: pool-2-thread-1, time: 13:58:05.599712400
Finished running method MyBean.runTask
-------
task 2 thread: pool-1-thread-1, time: 13:58:05.608682600
task thread: pool-1-thread-1, time: 13:58:05.609678900
Running method MyBean.runTask
task thread: pool-2-thread-1, time: 13:58:06.602690300
Finished running method MyBean.runTask
-------
task thread: pool-1-thread-1, time: 13:58:06.610445
task 2 thread: pool-1-thread-1, time: 13:58:07.531037300
Running method MyBean.runTask2
task 2 thread: pool-2-thread-1, time: 13:58:07.533085600
Finished running method MyBean.runTask2
-------
Running method MyBean.runTask
task thread: pool-2-thread-1, time: 13:58:07.603913900
Finished running method MyBean.runTask
-------
task thread: pool-1-thread-1, time: 13:58:07.611711700
Running method MyBean.runTask
task thread: pool-1-thread-1, time: 13:58:08.619743700
task thread: pool-2-thread-1, time: 13:58:08.619743700
Finished running method MyBean.runTask
-------
Running method MyBean.runTask2
task 2 thread: pool-1-thread-1, time: 13:58:09.539502
task 2 thread: pool-2-thread-1, time: 13:58:09.539502
Finished running method MyBean.runTask2
-------
Running method MyBean.runTask
task thread: pool-1-thread-1, time: 13:58:09.633156400
task thread: pool-2-thread-1, time: 13:58:09.633156400
Finished running method MyBean.runTask
-------
.....................

Example Project

Dependencies and Technologies Used:

  • spring-context 6.2.12 (Spring Context)
     Version Compatibility: 6.1.0 - 6.2.12Version List
    ×

    Version compatibilities of spring-context with this example:

    • 6.1.0
    • 6.1.1
    • 6.1.2
    • 6.1.3
    • 6.1.4
    • 6.1.5
    • 6.1.6
    • 6.1.7
    • 6.1.8
    • 6.1.9
    • 6.1.10
    • 6.1.11
    • 6.1.12
    • 6.1.13
    • 6.1.14
    • 6.1.15
    • 6.1.16
    • 6.1.17
    • 6.1.18
    • 6.1.19
    • 6.1.20
    • 6.1.21
    • 6.2.0
    • 6.2.1
    • 6.2.2
    • 6.2.3
    • 6.2.4
    • 6.2.5
    • 6.2.6
    • 6.2.7
    • 6.2.8
    • 6.2.9
    • 6.2.10
    • 6.2.11
    • 6.2.12

    Versions in green have been tested.

  • JDK 25
  • Maven 3.9.11

spring - Customized @Scheduled annotation processing by extending ScheduledAnnotationBeanPostProcessor Select All Download
  • spring-scheduled-annotation-customized-annotation-bean-post-processor
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • CustomScheduledBeanPostProcessor.java

    See Also