Spring Boot @Scheduled Annotation Example
Hello. In this tutorial, we will explain the Scheduled annotation in a spring boot application.
1. Introduction
@Scheduled
annotation in spring boot allows to schedule jobs in the applications. This annotation internally uses the task scheduler interface for scheduling the annotated methods for execution. To set up the spring boot scheduler we need to understand the following –
@EnableScheduling
– Enables the support for scheduling functionality in our application. The annotation is added to the main class- Ways to implement scheduling:
- The
fixedDelay
option specifies the fixed duration between the end of the previous task and the beginning of the new task. The new task only starts after the previous ends. TheinitialDelay
parameter offers to delay the first execution of the task with the specified number of milliseconds - Adding the
fixedRate
option makes the tasks to be executed in parallel. To make it happen the methods are annotated with the@Async
annotation. TheinitialDelay
parameter offers to delay the first execution of the task with the specified number of milliseconds - Adding the
cron
option makes scheduling work in a more advanced manner
- The
2. Spring Boot @Scheduled Annotation Example
Let us dive into some practice stuff and I am hoping that you are aware of the spring boot basics.
2.1 Tools Used for Spring boot application and Project Structure
We are using Eclipse Kepler SR2, JDK 8, and Maven. In case you’re confused about where you should create the corresponding files or folder, let us review the project structure of the spring boot application.
Let us start building the application!
3. Creating a Spring Boot application
Below are the steps involved in developing the application.
3.1 Maven Dependency
In the pom.xml
file we will define the required dependencies.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <artifactId>springbootscheduledannotation</artifactId> <build> <plugins> <plugin> <artifactId>spring-boot-maven-plugin</artifactId> <groupId>org.springframework.boot</groupId> </plugin> </plugins> </build> <dependencies> <dependency> <artifactId>spring-boot-starter-data-jpa</artifactId> <groupId>org.springframework.boot</groupId> </dependency> <dependency> <artifactId>spring-boot-starter-web</artifactId> <groupId>org.springframework.boot</groupId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.github.javafaker</groupId> <artifactId>javafaker</artifactId> <version>1.0.2</version> </dependency> <dependency> <artifactId>spring-boot-starter-test</artifactId> <groupId>org.springframework.boot</groupId> <scope>test</scope> </dependency> </dependencies> <description>Demo project for Spring Boot</description> <groupId>com.springboot</groupId> <modelVersion>4.0.0</modelVersion> <name>springbootscheduledannotation</name> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <relativePath /> <version>2.5.6</version> <!-- lookup parent from repository --> </parent> <properties> <java.version>1.8</java.version> </properties> <version>0.0.1-SNAPSHOT</version> </project>
3.2 Application yml file
Create a yml file in the resources
folder and add the following content to it. The file will contain information about the scheduling, database connectivity, and spring jpa.
application.yml
fixedDelay: in: milliseconds: 10000 server: port: 9050 spring: application: name: springboot-scheduler datasource: driverClassName: org.h2.Driver password: "" url: "jdbc:h2:mem:currency" username: sa h2: console: enabled: false path: /h2-console jpa: database-platform: org.hibernate.dialect.H2Dialect hibernate: ddl-auto: create-drop show_sql: true
3.3 Java Classes
Let us write the important java class(es) involved in this tutorial. The other non-important classes for this tutorial like the main, controller, and repository can be downloaded from the Downloads section.
3.3.1 Model class
Create a model class that will be responsible for schema and data in the sql table.
Currency.java
package com.demo.model; import java.time.ZonedDateTime; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @Builder @Entity @Table(name = "currency") public class Currency { @Id @GeneratedValue(strategy = GenerationType.AUTO) int id; String name; String code; @Column(name = "created_on") ZonedDateTime createdOn; }
3.3.2 Service class
Add the following code to the service class that shows the implementation of the scheduled annotation. The methods annotated with the annotation will –
prepareData()
– Execute every 10 seconds to push a new record to the sql table. The expression specified in the annotation will be read from theapplication.yml
performCleanup()
– Execute at every 5 minutes to remove the older data
Other methods will be responsible to fetch the data from the sql table and pass it to the controller for showing to the user. You can download the controller file from the Downloads section.
CurrencyService.java
package com.demo.service; import java.time.ZonedDateTime; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import com.demo.model.Currency; import com.demo.repository.CurrencyRepository; import com.github.javafaker.Faker; import lombok.extern.slf4j.Slf4j; @Slf4j @Service public class CurrencyService { @Autowired CurrencyRepository repo; static final Faker FAKER = new Faker(); public List<Currency> getAll() { log.info("Fetching currencies"); return repo.findAll(); } public Currency getByCode(String code) throws Exception { log.info("Fetching currency for code = {}", code); // since we do not have any duplicate check we are adding this hackish way. return repo.findFirstByCode(code) .orElseThrow(() -> new Exception("CURRENCY_NOT_FOUND")); } // method will be executed at every Xsec with an initial delay of 1sec // initial delay ensures that 1st execution of the task happens after 1sec // parameterize the scheduling param. will be read from properties file @Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds}", initialDelay = 1000) private void prepareData() { ZonedDateTime now = ZonedDateTime.now(); Currency c = Currency.builder() .name(FAKER.currency().name()) .code(FAKER.currency().code()) .createdOn(now) .build(); log.info("Saving currency"); repo.save(c); } // https://web.archive.org/web/20150317024908/http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06 // method will run every 5mins @Scheduled(cron = "0 0/5 * * * ?") private void performCleanup() { ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime nowMinusFiveMins = now.minusMinutes(5); log.info("Running cleanup at {} to remove records before {}", now, nowMinusFiveMins); repo.deleteByCreatedOnBefore(nowMinusFiveMins); } }
4. Run the main class
To run the application, right-click on the SpringbootscheduledannotationApplication.java
class, Run As -> Spring Boot App
. If everything goes well the application will be started successfully. Once the application is started, keep an eye on the logs which will show that every 10th second save scheduler will be invoked to save a record to the sql table and every 5th minute the cleanup scheduler will be invoked to remove the older records. Below is the snippet of the logs generated during the dry run.
Logs snippet
2021-11-08 21:49:30.932 INFO 19804 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 9050 (http) with context path '' 2021-11-08 21:49:30.941 INFO 19804 --- [ main] SpringbootscheduledannotationApplication : Started SpringbootscheduledannotationApplication in 2.842 seconds (JVM running for 3.888) 2021-11-08 21:49:30.943 INFO 19804 --- [ main] SpringbootscheduledannotationApplication : App started 2021-11-08 21:49:31.969 INFO 19804 --- [ scheduling-1] com.demo.service.CurrencyService : Saving currency Hibernate: call next value for hibernate_sequence Hibernate: insert into currency (code, created_on, name, id) values (?, ?, ?, ?) 2021-11-08 21:49:42.024 INFO 19804 --- [ scheduling-1] com.demo.service.CurrencyService : Saving currency Hibernate: call next value for hibernate_sequence Hibernate: insert into currency (code, created_on, name, id) values (?, ?, ?, ?) 2021-11-08 21:49:52.042 INFO 19804 --- [ scheduling-1] com.demo.service.CurrencyService : Saving currency Hibernate: call next value for hibernate_sequence Hibernate: insert into currency (code, created_on, name, id) values (?, ?, ?, ?) 2021-11-08 21:49:55.054 INFO 19804 --- [nio-9050-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-11-08 21:49:55.055 INFO 19804 --- [nio-9050-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2021-11-08 21:49:55.056 INFO 19804 --- [nio-9050-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms 2021-11-08 21:49:55.096 INFO 19804 --- [nio-9050-exec-1] com.demo.service.CurrencyService : Fetching currencies Hibernate: select currency0_.id as id1_0_, currency0_.code as code2_0_, currency0_.created_on as created_3_0_, currency0_.name as name4_0_ from currency currency0_ 2021-11-08 21:50:00.014 INFO 19804 --- [ scheduling-1] com.demo.service.CurrencyService : Running cleanup at 2021-11-08T21:50:00.014+05:30[Asia/Calcutta] to remove records before 2021-11-08T21:45:00.014+05:30[Asia/Calcutta] Hibernate: select currency0_.id as id1_0_, currency0_.code as code2_0_, currency0_.created_on as created_3_0_, currency0_.name as name4_0_ from currency currency0_ where currency0_.created_on<!--? 2021-11-08 21:50:02.049 INFO 19804 --- [ scheduling-1] com.demo.service.CurrencyService : Saving currency Hibernate: call next value for hibernate_sequence Hibernate: insert into currency (code, created_on, name, id) values (?, ?, ?, ?)
5. Project Demo
Once the application is started successfully we can use the controller endpoints to play around and get the data from the sql table. To test we will use the postman tool. However, you’re free to use any tool of your choice for interacting with the application endpoints.
Application endpoints
-- get a currency by code -- http://localhost:9050/currency/get?code=SYP -- get currencies -- http://localhost:9050/currency
That is all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and do not forget to share!
6. Summary
In this tutorial, we explained the Scheduled annotation in a spring boot application.. The annotation is responsible to scheduled jobs in the application and offer variation such as fixedDelay
, fixedRate
, and cron
. You can download the sample application as an Eclipse project in the Downloads section.
7. Download the Project
This was an example of @Scheduled
annotation implementation in a sping application.
You can download the full source code of this example here: Spring Boot @Scheduled Annotation Example