Ebooks

Spring Boot ApplicationReadyEvent tutorial

Spring Boot ApplicationReadyEvent tutorial shows how to execute a task when an application is ready.

A Spring Boot application issues various events. We can use listeners to react to such events.

For instance, the ApplicationStartedEvent is sent after the context has been refreshed but before any application and command-line runners have been called. The ApplicationReadyEvent is sent after any application and command-line runners have been called. It indicates that the application is ready to service requests.

Spring Boot ApplicationReadyEvent example

The following Spring Boot application is a simple web application that triggers a web request in reaction to the ApplicationStartedEvent. The request is made with WebClient.

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           ├───bean
│   │           │       TimeResponse.java
│   │           ├───event
│   │           │       AppEvents.java
│   │           └───routes
│   │                   AppRoutes.java
│   └───resources
└───test
    └───java
        └───com
            └───zetcode
                └───routes
                        AppRoutesTest.java

This is the project structure.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>applicationreadyevent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

        </plugins>
    </build>

</project>

This is the Maven build file. The spring-boot-starter-webflux is starter for building WebFlux applications using Spring Framework's Reactive Web support.

com/zetcode/bean/TimeResponse.java
package com.zetcode.bean;

public class TimeResponse {

    private String date;
    private Long unixtime;
    private String time;

    public String getDate() {

        return date;
    }

    public void setDate(String date) {

        this.date = date;
    }

    public Long getUnixtime() {

        return unixtime;
    }

    public void setUnixtime(Long unixtime) {

        this.unixtime = unixtime;
    }

    public String getTime() {

        return time;
    }

    public void setTime(String time) {

        this.time = time;
    }

    @Override
    public String toString() {

        final StringBuilder sb = new StringBuilder("TimeResponse{");
        sb.append("date='").append(date).append('\'');
        sb.append(", unixtime=").append(unixtime);
        sb.append(", time='").append(time).append('\'');
        sb.append('}');

        return sb.toString();
    }
}

This is the TimeResponse bean. It is used to store data from the web request.

com/zetcode/event/AppEvents.java
package com.zetcode.event;

import com.zetcode.bean.TimeResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@Component
public class AppEvents {

    private static final Logger logger = LoggerFactory.getLogger(AppEvents.class);

    @EventListener(ApplicationReadyEvent.class)
    public void startApp() {

        var webClient = WebClient.create("http://time.jsontest.com/");

        Mono<TimeResponse> result = webClient.get()
                .retrieve()
                .bodyToMono(TimeResponse.class);

        result.subscribe(res -> logger.info("{}", res));
    }
}

In AppEvents we create a simple GET request.

@EventListener(ApplicationReadyEvent.class)
public void startApp() {

With @EventListener annotation, we register for the ApplicationReadyEvent.

var webClient = WebClient.create("http://time.jsontest.com/");

From the http://time.jsontest.com/, we get the current time.

Mono<TimeResponse> result = webClient.get()
    .retrieve()
    .bodyToMono(TimeResponse.class);

result.subscribe(res -> logger.info("{}", res));

With WebClient, we create a GET request to the site and output the result to the terminal.

com/zetcode/routes/AppRoutes.java
package com.zetcode.routes;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

@Configuration
public class AppRoutes {

    @Bean
    RouterFunction<ServerResponse> home() {

        return route(GET("/"), request -> ok().syncBody("Home page"));
    }
}

Our application uses a functional web framework to return a simple message for the home page.

com/zetcode/Application.java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

The Application sets up the Spring Boot application

com/zetcode/routes/AppRoutesTest.java
package com.zetcode.routes;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AppRoutesTest {

    @Autowired
    private WebTestClient client;

    @Test
    public void test_home_page() {

        client.get().uri("/").exchange().expectStatus().isOk()
                .expectBody(String.class).isEqualTo("Home page");
    }
}

With WebTestClient, we create a test method for the home page.

...
2019-06-21 16:40:45.214  INFO 9356 --- [ctor-http-nio-5] com.zetcode.event.AppEvents : TimeResponse{date='06-21-2019', unixtime=null, time='02:40:47 PM'}
...

When the application starts, we get this message to the terminal.

List all Spring Boot tutorials.