Learn How to write Scheduled Tasks Using @Scheduled Annotation in Spring.
Tutorial Contents
Overview
Often, we need to write Scheduled Tasks or Scheduled Methods that is executed as per the given schedule. And, such scheduled tasks have a variety of use cases including a scheduled batch processing, or a nightly job that fetches data every night. The scheduled methods are executed asynchronously while the other parts of the application continue to work independently.
In this tutorial we will see how can we use Spring to easily write scheduled methods. We will also cover the four ways of Scheduling tasks using Spring.
Spring @Scheduled Annotation
Spring Framework has excellent support to the method scheduling. Using the @Scheduled
annotation, we can convert almost any method in the application to a Scheduled Method.
The
is a method level annotation and we need to add it on a method of a Spring Bean class. We can provide parameters to the annotations to specify if we wish the method to be executed on a fixed interval or at a specific schedule of time and date. @Scheduled
Enable Scheduling in Spring Application
By default, the Scheduled processing is disabled in a. Spring Application. In order to Enable scheduling in Spring Application we need to add @EnableScheduling
annotation on a Configuration.
Next is an example of the Application class in our Spring Boot project. Notice that the class has the @EnableScheduling
annotation.
package com.amitph.spring.tutorials.springbootdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Code language: Java (java)
Or, next is an example of Enabling Scheduling using Spring XML Configuration.
<task:annotation-driven>
Code language: HTML, XML (xml)
When the @EnableScheduling
annotation or the annotation-driven
tag is detected, Spring scans the application packages to find all the Spring Beans having @Scheduled
methods and set up their execution schedule.
Now, we have done everything that is required to add Scheduled Methods in Spring Boot Application. We can schedule a method at a fixed delay, a fixed rate or on a specific cron schedule. Before we move ahead let’s understand Fixed Delay vs Fixed Rate.
Difference Between Fixed Delay and Fixed Rate Scheduling
As stated earlier, in Spring we use @Scheduled
annotation on a method to schedule its execution. While doing so we can use properties like fixedDelay
or fixedRate
to specify a number of milliseconds.
When a fixedDelay is specified, the next execution will only begin a specified number of milliseconds after the previous execution is finished. On the other hand, when fixedRate is used, the next execution will begin a specified number of milliseconds after the start of previous one.
The fixedDelay
should be used, when the executions are dependent on each other and we always we wish the next execution to start only a certain while after the first finishes.
However, the fixedRate
should be used when the rate of of the execution matters more and it is irrespective of the time each execution takes to finish.
Scheduled Task with Fixed Delay
See the example to Schedule a task to run after a fixed delay of 2 seconds.
@Scheduled(fixedDelay = 2000)
public void taskWithFixedDelay() {
logger.info("Task with Fixed Delay, " + (LocalTime.now().getSecond()));
}
Code language: Java (java)
Spring executes the above method at a fixed delay of 2 seconds. Which means, the duration between the end of first execution and the start of the next will always be 2 seconds. In other words, the next execution won’t start until the specific fixed delay is elapsed after the completion of the current execution.
Scheduled Task at Fixed Rate
Next, is an example of of scheduling a method at a fixed interval.
@Scheduled(fixedRate = 2000)
public void taskWithFixedRate() throws InterruptedException {
logger.info("Task with Fixed Rate, " + (LocalTime.now().getSecond()));
MILLISECONDS.sleep(1000L);
}
Code language: Java (java)
When we set fixedRate
value, the next execution will be triggered when the given number of milliseconds are elapsed from the beginning of the current execution. That is why, when we run the above, we can see the method is executed at a fixed interval of 2 seconds, irrespective of the sleep time of 1 second.
However, it is important to know that scheduling cannot run two executions concurrently. Which means, if the sleep time exceeds the specified fixed rate value, the next execution will wait until the previous execution is finished.
Allow Concurrent Executions of Scheduled Tasks
If we wish to allow concurrent execution of these scheduled methods we can do by used @EnableAsync
and @Async
annotations.
@Component
@EnableAsync
public class ScheduledTask {
private final Logger logger = LoggerFactory.getLogger(ScheduledTask.class);
@Scheduled(fixedRate = 2000)
@Async
public void taskWithFixedRate() throws InterruptedException {
logger.info("Task with Fixed Rate, " + (LocalTime.now().getSecond()));
MILLISECONDS.sleep(4000L);
}
}
Code language: Java (java)
In the above example, the sleep time is more than the fixed interval. However, as we have enabled the asynchronous execution, the method will be executed concurrently, at the fixed rate of 2 seconds.
Scheduled Tasks with Initial Delay
We can schedule a task having initial delay by using initialDelay
property.
@Scheduled(fixedRate = 3000, initialDelay = 10000)
public void taskWithFixedRateAndInitialDelay(){
logger.info("Task with Fixed Rate and Initial Delay, " + (LocalTime.now().getSecond()));
}
Code language: Java (java)
We can use initialDelay
along with both fixedRate
and fixedDelay
type of scheduling. When initialDelay
is set, the first execution of the method won’t start until the specified number of milliseconds are passed. Also, the initialDelay
as no impact on the subsequent executions of the task.
Scheduled Task using Cron Expressions
We can use cron
property to specify a cron expression to define the execution schedule of a method. Using cron expression we can provide a more complex, a more flexible schedule for the tasks.
@Scheduled(cron = "0 45 1,2,3 * * ?", zone = "Europe/London")
public void taskWithCronExpression(){
logger.info("Task with Cron Expression, " + (LocalTime.now().getSecond()));
}
Code language: Java (java)
Here, we have scheduled our method to execute it on 1:45 AM, 2:45 AM, and 3:45 AM everyday. We can also specify the optional field of zone
to provide a specific timezone. The scheduler will execute this method once the given time is reached in London.
Reading the Schedule from Properties File
So far, we have hard coded the Task Schedules. However, we can also keep these schedules in a properties file and refer them using Spring Expressions.
Next, is an example of a properties file
schedule.fixedDelay=2000
schedule.fixedRate=2000
schedule.initialDelay=10000
schedule.cron=0 45 1,2,3 * * ?
schedule.timezone=Europe/London
Code language: Properties (properties)
We can refer to these properties using Spring Expressions and shown next.
package com.amitph.spring.tutorials.springbootdemo.scheduled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalTime;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
@Component
@EnableAsync
public class ScheduledTask {
private final Logger logger = LoggerFactory.getLogger(ScheduledTask.class);
@Scheduled(fixedDelayString = "${schedule.fixedDelay}")
public void taskWithFixedDelay() {
logger.info("Task with Fixed Delay, " + (LocalTime.now().getSecond()));
}
@Scheduled(fixedRateString = "${schedule.fixedRate}")
@Async
public void taskWithFixedRate() throws InterruptedException {
logger.info("Task with Fixed Rate, " + (LocalTime.now().getSecond()));
MILLISECONDS.sleep(4000L);
}
@Scheduled(fixedRateString = "${schedule.fixedRate}", initialDelayString = "${schedule.initialDelay}")
public void taskWithFixedRateAndInitialDelay() {
logger.info("Task with Fixed Rate and Initial Delay, " + (LocalTime.now().getSecond()));
}
@Scheduled(cron = "${schedule.cron}", zone = "${schedule.timezone}")
public void taskWithCronExpression() {
logger.info("Task with Cron Expression, " + (LocalTime.now().getSecond()));
}
}
Code language: Java (java)
Note that, the fixedRate
, fixedDelay
, and initialDelay
properties are numeric. However, the Spring expression substitution happens as String. That is why, we are using the fixedRateString
, fixedDelayString
, and initialDelayString
variants of these properties respectively.
Summary
In this tutorial we learned How to Write Scheduled Tasks in Spring using @Scheduled
annotation. We started by understanding that we need to enable Scheduling by using @EnableScheduling
. Most importantly, we covered all four ways of Scheduling tasks in Spring. We have also referred to various Scheduled tasks in a Spring Boot Application.
To learn more about Spring and Spring boot please visit Introduction to Spring Framework and Spring Boot Introduction.
For full source code of the examples used here, please visit our Github Repository.