Boot

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. The initialDelay 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. The initialDelay 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

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.

spring boot scheduled - project structure
Fig. 1: Project structure

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 the application.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.

Download
You can download the full source code of this example here: Spring Boot @Scheduled Annotation Example

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button