Software Development

How To Run Custom Code on Micronaut Start

When building applications with Micronaut, there are times when you need to run specific logic as soon as the application starts — for example, initializing resources, preloading caches, validating configurations, or logging startup metrics. Let us delve into understanding how to run startup code when micronaut starts.

1. Understanding Micronaut and Flyway

Micronaut provides a flexible way to hook into the application lifecycle using various events. These events can be used to trigger custom logic at specific stages of your application’s startup or shutdown. The two most common approaches to execute code during the startup phase are:

  • Implementing ApplicationEventListener: You can create a bean that listens to specific lifecycle events like StartupEvent by implementing ApplicationEventListener<StartupEvent>. This gives you full control and allows for logic execution at precise moments.
  • Using @EventListener: A more concise, annotation-based approach to listen for events. Simply annotate a method in a bean with @EventListener and define the event type as a method parameter (e.g., StartupEvent).

These methods are ideal for initializing resources, pre-loading configuration, registering services, or performing health checks—tasks that must run before your application starts serving incoming requests. For more on Micronaut’s lifecycle and events, refer to the official Micronaut Event Listeners Guide.

2. Code Example

Here’s how you can create a complete Micronaut project that includes the necessary dependencies, configuration files, and structure to run startup code.

2.1 Add dependencies (build.gradle)

Generate a Micronaut project using either the Micronaut CLI or the Micronaut Launch website. By default, Micronaut includes the essential dependencies. However, we’ll verify that all required dependencies are present in the build.gradle file and make any necessary edits to ensure the project is properly configured.

dependencies {
    implementation 'io.micronaut:micronaut-runtime'
    implementation 'io.micronaut:micronaut-inject'
    implementation 'jakarta.inject:jakarta.inject-api:compatible__jar__version'
    runtimeOnly 'ch.qos.logback:logback-classic:compatible__jar__version''
    testImplementation 'io.micronaut:micronaut-test'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:compatible__jar__version''
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:compatible__jar__version''
    testImplementation 'org.mockito:mockito-core:compatible__jar__version''
}

2.2 Write Startup Listener Code

Now, let’s create the Java classes for the startup event listener.

2.2.1 Using ApplicationEventListener Interface

Create a class called StartupListener.java inside the src/main/java/com/example/startup directory.

package com.example.startup;

import io.micronaut.context.event.ApplicationEventListener;
import io.micronaut.runtime.event.ApplicationStartupEvent;
import jakarta.inject.Singleton;

@Singleton
public class StartupListener implements ApplicationEventListener {

    @Override
    public void onApplicationEvent(ApplicationStartupEvent event) {
        System.out.println("Application has started. Running startup code...");
        initializeResources();
    }

    private void initializeResources() {
        System.out.println("Initializing resources...");
        // Simulate some startup logic
    }
}

The above code defines a Micronaut singleton class StartupListener that implements ApplicationEventListener with a generic type of ApplicationStartupEvent. This allows the class to listen for the application’s startup event. When the Micronaut application starts, the onApplicationEvent method is automatically triggered, printing a message to the console and calling the initializeResources() method. This method simulates the initialization of resources required at startup, making it a good place to execute custom logic such as loading configuration, connecting to external systems, or pre-warming caches.

2.2.2 Using EventListener Annotation

Create a class called AnnotatedStartupListener.java inside the src/main/java/com/example/startup directory.

package com.example.startup;

import io.micronaut.runtime.event.annotation.EventListener;
import io.micronaut.runtime.event.ApplicationStartupEvent;
import jakarta.inject.Singleton;

@Singleton
public class AnnotatedStartupListener {

    @EventListener
    public void onStartup(ApplicationStartupEvent event) {
        System.out.println("App started - @EventListener triggered!");
        performStartupTasks();
    }

    private void performStartupTasks() {
        System.out.println("Executing annotated startup tasks...");
        // Custom logic here
    }
}

The above code defines a Micronaut bean AnnotatedStartupListener annotated with @Singleton, which uses the @EventListener annotation to listen for the ApplicationStartupEvent. When the application starts, the onStartup method is automatically invoked, printing a message and calling the performStartupTasks() method. This method is intended to hold any custom startup logic such as initializing services, loading data, or setting up connections. The use of @EventListener provides a declarative and cleaner way to handle lifecycle events compared to implementing interfaces.

2.3 Create Main Application Class

The Application.java class will serve as the entry point for the application.

package com.example.startup;

import io.micronaut.runtime.Micronaut;

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

2.4 Configuration File

If you want to configure the application as per your requirements, you can modify the src/main/resources/application.yml file for Micronaut settings.

micronaut:
  application:
    name: startup
  server:
    port: 8080

2.5 Running the Application

Once the code is set up, you can run your Micronaut application using the following Gradle command:

./gradlew run

You should see the startup messages printed in the terminal, such as:

-- ApplicationEventListener interface --

Application has started. Running startup code...
Initializing resources...

-- @EventListener annotation  –

App started - @EventListener triggered!
Executing annotated startup tasks...

3. Conclusion

Micronaut provides powerful and flexible mechanisms to hook into the application lifecycle. Whether you prefer the explicit interface-based approach using ApplicationEventListener or the more concise @EventListener annotation, you can easily insert custom logic during startup. These mechanisms help keep your application clean, modular, and reactive to its own lifecycle. By leveraging these features, you can efficiently initialize necessary resources, preload data, or configure services that your application will need throughout its runtime. Choose the approach that best suits your application’s needs and scale your startup logic accordingly.

Yatin Batra

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
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button