Close

Spring - Task Scheduling using @Scheduled

[Last Updated: Jan 26, 2017]

Spring provides annotation support for scheduling method execution using @Scheduled and @EnableScheduling.



Simple use of @Scheduled and @EnableScheduling

Annotate the configuration class with @EnableScheduling

@EnableScheduling
@Configuration
public class MyConfig {
    @Bean
    public MyBean myBean () {
        return new MyBean();
    }
}

Use @Scheduled on bean's methods:

public class MyBean {

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

       try {
           Thread.sleep(500);
       } catch (InterruptedException e) {
       }
   }
}

Calling @Scheduled method from main method:

public class ScheduledExample {

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

        MyBean bean = context.getBean(MyBean.class);
        System.out.printf("calling MyBean#runTask() thread: %s%n",
                          Thread.currentThread().getName());
        bean.runTask();
        System.out.println("call MyBean#runTask() returned");

        //exit after 5 secs
        Thread.sleep(5000);
        System.exit(0);
    }
}

Output

calling MyBean#runTask() thread: main
Running scheduled task  thread: pool-1-thread-1, time: 22:15:07.996
Running scheduled task  thread: main, time: 22:15:07.997
call MyBean#runTask() returned
Running scheduled task  thread: pool-1-thread-1, time: 22:15:08.984
Running scheduled task  thread: pool-1-thread-1, time: 22:15:09.984
Running scheduled task  thread: pool-1-thread-1, time: 22:15:10.985
Running scheduled task  thread: pool-1-thread-1, time: 22:15:11.985
Running scheduled task  thread: pool-1-thread-1, time: 22:15:12.984



Using TaskScheduler other than default:

To specify a custom TaskScheduler we just need to configure it as a bean:

@EnableScheduling
@Configuration
public class MyConfig {
    @Bean
    public MyBean myBean () {
        return new MyBean();
    }

    @Bean
    public TaskScheduler taskExecutor () {
        return new ConcurrentTaskScheduler(
                  Executors.newScheduledThreadPool(3));
    }
}
public class MyBean {

    @Scheduled(fixedDelay = 1000)
    public void runTask () {
        System.out.printf("task thread: %s, time: %s%n",
                          Thread.currentThread().getName(),
                          LocalTime.now());
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
        }
    }
}
public class ScheduledOverrideDefaultExecutorExample {

    public static void main (String[] args) throws Exception {
        AnnotationConfigApplicationContext context =
                  new AnnotationConfigApplicationContext(
                            MyConfig.class);
        MyBean bean = context.getBean(MyBean.class);
        bean.runTask();
        System.out.println("call MyBean#runTask() returned");

        Thread.sleep(3000);
        System.out.println("Shutting down after 3 secs");
        ConcurrentTaskExecutor exec =
                     (ConcurrentTaskExecutor) context.getBean("taskExecutor");
        ExecutorService es = (ExecutorService) exec.getConcurrentExecutor();
        es.shutdownNow();
    }
}
task thread: main, time: 22:37:25.202
task thread: pool-1-thread-1, time: 22:37:25.202
call MyBean#runTask() returned
task thread: pool-1-thread-1, time: 22:37:26.742
task thread: pool-1-thread-2, time: 22:37:28.244
Shutting down after 3 secs



@Scheduled method arguments and return value

The methods annotated with @Scheduled must have void returns and must not have any arguments. This is because of it's periodic nature where passing an argument or receiving a return value won't make much sense.

Following example shows that violating this rules will end up with an exception.

@EnableScheduling
@Configuration
public class MyConfig {
    @Bean
    public MyBean myBean () {
        return new MyBean();
    }
}
public class MyBean {

    @Scheduled
    public String runTask (String message) {
        System.out.printf("task thread: %s, time: %s%n",
                          Thread.currentThread().getName(),
                          LocalTime.now());
        System.out.printf("message: %s%n", message);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
        }
        return "return value";
    }
}
public class ScheduledMethodArgExample {

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

        MyBean bean = context.getBean(MyBean.class);
        System.out.printf("calling MyBean#runTask() thread: %s%n",
                          Thread.currentThread().getName());
        String s = bean.runTask("from main");
        System.out.println("call MyBean#runTask() returned");
        System.out.println("returned value: " + s);
    }
}

Output

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myBean' defined in com.logicbig.example.ScheduledMethodArgExample$MyConfig: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Encountered invalid @Scheduled method 'runTask': Only no-arg methods may be annotated with @Scheduled
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:754)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.
 
  (AnnotationConfigApplicationContext.java:84)
	at com.logicbig.example.ScheduledMethodArgExample.main(ScheduledMethodArgExample.java:14)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.IllegalStateException: Encountered invalid @Scheduled method 'runTask': Only no-arg methods may be annotated with @Scheduled
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.processScheduled(ScheduledAnnotationBeanPostProcessor.java:413)
	at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.postProcessAfterInitialization(ScheduledAnnotationBeanPostProcessor.java:283)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1588)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
	... 15 more
 



Using SchedulingConfigurer

The interface SchedulingConfigurer can be implemented by @Configuration classes to provide scheduled tasks without using @Scheduled annotation on beans but still on a JavaConfig level:

@EnableScheduling
@Configuration
public class MyConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks (ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addFixedDelayTask(() -> {
            System.out.println("Running task : "+LocalTime.now());

        }, 500);
    }
}
public class SchedulingConfigurerExample {

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

      Thread.sleep(5000);
      System.out.println(" -- Exiting application after 5 sec -- ");
      System.exit(0);

  }
}

Output

Running task : 23:21:34.588
Running task : 23:21:35.093
Running task : 23:21:35.594
Running task : 23:21:36.094
Running task : 23:21:36.595
Running task : 23:21:37.096
Running task : 23:21:37.598
Running task : 23:21:38.099
Running task : 23:21:38.600
Running task : 23:21:39.101
 -- Exiting application after 5 secs--

Using SchedulingConfigurer is necessary when implementing Trigger-based tasks, which are not supported by the @Scheduled annotation.




Cron and other scheduling configuration

@Scheduled annotation allows various configurations elements to allow us different ways to schedule tasks, which includes cron expression, scheduling frequency and initial delay etc. Please check out @Scheduled API doc.



Example Project

Dependencies and Technologies Used:

  • Spring Context 4.3.4.RELEASE: Spring Context.
  • JDK 1.8
  • Maven 3.3.9

Spring Scheduled Annotation Examples Select All Download
  • spring-core-scheduled-annotation
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ScheduledExample.java

    See Also