Standalone Micronaut Application

Luis Gustavo
5 min readJan 30, 2021

So you want to have dependency injection in your new Java playground, but don’t want to mess with XML from Spring Context? In this article you’ll find out how! πŸ˜ƒ

Photo by John Baker on Unsplash

A Sneak Peak of the End

After following this guide, you’ll have a simple Java application, with compile-time generated dependency injection capabilities, along with a few more nice features from Micronaut, like the Configuration Properties and the AOP.

If you just want to see the final result, here is the repository:

So, without further ado, let’s dive into the tutorial:

1. Generating the project

I’ll use Gradle as my build tool so we can take advantage of the new Micronaut Gradle Plugin. And before I forget, I’ll be using JDK version 15, but I think anything above 11 will do.

So begin by first creating a new folder and make sure to open a terminal inside it:

mkdir awesome-micronaut-app && cd awesome-micronaut-app

After that, we can initialize an empty Gradle project

gradle init

We want an application, so make sure to answer 2: application when asked by the process. Following the questions, we want a Java app, so 3: Java . For the sake of simplicity, I’ll stick with a single application, without subprojects, so for the next question, the answer should be: 1: no, only one application project . Groovy Build Script, JUnit Jupiter as the test framework, and lastly choose a name for your app.

After the project is created, you’ll probably have a folder structure like:

β”œβ”€β”€ app
β”‚ β”œβ”€β”€ build.gradle
β”‚ └── src
β”‚ β”œβ”€β”€ main
β”‚ β”‚ β”œβ”€β”€ java
β”‚ β”‚ β”‚ └── com
β”‚ β”‚ β”‚ └── awesome
β”‚ β”‚ β”‚ └── micronaut
β”‚ β”‚ β”‚ └── App.java
β”‚ β”‚ └── resources
β”‚ └── test
β”‚ β”œβ”€β”€ java
β”‚ β”‚ └── com
β”‚ β”‚ └── awesome
β”‚ β”‚ └── micronaut
β”‚ β”‚ └── AppTest.java
β”‚ └── resources
β”œβ”€β”€ gradle
β”‚ └── wrapper
β”‚ β”œβ”€β”€ gradle-wrapper.jar
β”‚ └── gradle-wrapper.properties
β”œβ”€β”€ gradlew
β”œβ”€β”€ gradlew.bat
└── settings.gradle

2. Configuring Micronaut

To be able to use the awesome Micronaut features we need to import then in some way, so let’s get that done!

Before touching anything, we need to open the project in a text editor or IDE, you can use IntelliJ, VSCode, or any other IDE/text editor you’re familiar with.

So after you’ve opened the folder in your favorite IDE, we need to change a few things in the app/build.gradle . Check out the full file below, paying attention to the changes in bold (comments removed for brevity):

plugins {
id 'application'
}
ext {
micronautVersion = '2.3.0'
}
repositories {
jcenter()
mavenCentral();
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
implementation 'com.google.guava:guava:29.0-jre'
// Micronaut Dependencies
annotationProcessor(platform("io.micronaut:micronaut-bom:${micronautVersion}"))
annotationProcessor("io.micronaut:micronaut-inject-java")
implementation(platform("io.micronaut:micronaut-bom:${micronautVersion}"))
implementation("io.micronaut:micronaut-inject")
implementation("io.micronaut:micronaut-aop")
testAnnotationProcessor(platform("io.micronaut:micronaut-bom:${micronautVersion}"))
testAnnotationProcessor("io.micronaut:micronaut-inject-java")
// To remove SLF4J warnings
runtimeOnly "org.slf4j:slf4j-simple"

}
application {
mainClass = 'com.awesome.micronaut.App'
}
java {
sourceCompatibility = JavaVersion.VERSION_15
targetCompatibility = JavaVersion.VERSION_15
}
tasks.named('test') {
useJUnitPlatform()
}

Remember to change the packages according to the name of your app. If something does not work for you, check out the full diff here.

After that, go to the terminal and install the dependencies and build the application (or just refresh Gradle in IntelliJ). Also the generated test class for the App class (AppTest.java) might break, so be sure to fix that before proceeding.

./gradlew clean build

And that’s it, you have a full blown Java application, with Dependency Injection, YML configuration, Application Event Listener/Publisher and much more!

If you know your way through Micronaut and how all this stuff works, you’re done, otherwise let’s see how we can put all this together in the following section.

3. Testing the available features

So, in this section you will see some of the things that are already working for you without out of the box.

3.1. Configuration Properties

Let’s create a very simple configuration properties binding, so we can use an application.yml file to store our app config.

import io.micronaut.context.annotation.ConfigurationProperties;@ConfigurationProperties("some.configuration")
public class SomeConfiguration {
private String value; public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
}

And also, lets create the configuration file at: src/main/resources/application.yml

some:
configuration:
value: "this tutorial is awesome!"

We will see it working in a few moments, let’s first add a few more features.

3.2. Application Events

Events are very popular nowadays, as a way to decouple the code. And is also very easy to implement with Micronaut.

We need three parts: an event β€” which will be published by someone; an event listener β€” who will react to specific events; and an event publisher β€” who will dispatch our events to the right listeners. But we only need to implement the event listener and the event itself, because Micronaut takes care of the publisher for us.

Both are very simple so let’s take a look at the implementation:

import io.micronaut.context.event.ApplicationEvent;public class SomeEvent extends ApplicationEvent {    public SomeEvent(Object source) {
super(source);
}
}

The event listener also has the @Singleton annotation so that the Micronaut runtime can find it and register it into the ApplicationContext .

import io.micronaut.context.event.ApplicationEventListener;import javax.inject.Singleton;@Singleton
public class SomeEventListener implements ApplicationEventListener<SomeEvent> {
@Override
public boolean supports(SomeEvent event) {
return true;
}
@Override
public void onApplicationEvent(SomeEvent event) {
System.out.println("Received an event!");
}
}

3.3. Dependency Injection

To wire it all together, let’s create a simple class and inject our configuration and the event publisher.

import io.micronaut.context.event.ApplicationEventPublisher;import javax.inject.Singleton;
import javax.inject.Inject;
@Singleton
public class SomeDependency {
@Inject
private SomeConfiguration someConfiguration;
@Inject
private ApplicationEventPublisher applicationEventPublisher;
public void doStuff() {
System.out.println("doing some stuff...");
}
public void publishEvent() {
System.out.println("publishing event...");
applicationEventPublisher.publishEvent(new SomeEvent(this));
}
public void consumeConfiguration() {
System.out.println("The configuration value is: " + someConfiguration.getValue());
}
}

3.4. The ApplicationContext

This is the last part, but is the most important one, because here we actually initialize Micronaut ApplicationContext, and it is where most of the magic happens (the other part being the annotation processing powers).

public static void main(String[] args) {
ApplicationContext applicationContext = ApplicationContext.run();
var dependency = applicationContext.getBean(SomeDependency.class); dependency.doStuff(); dependency.publishEvent(); dependency.consumeConfiguration();
}

Wew! That was a lot of code, it’s finally time to see some action!

So, if you followed along, and imported all the correct classes, when you run the β€œrun” Gradle task, you should see something like this:

> Task :app:run
doing some stuff...
publishing event...
Received an event!
The configuration value is: this tutorial is awesome!

And if you got any problems, check out the full code on the repo below:

4. Conclusion

I made this tutorial because I wanted to do some experiments with Micronaut without the Web Server part, and found it very difficult to find out the directions, so I hope this helps someone with the same problem.

Micronaut is a very interesting framework because it minimizes the use of reflection and instead use annotation processing to generate metadata at compile-time, making it very fast! I’ll probably write some more tutorials on the topic later down the road.

This article was my first full blown tutorial with code, so if you have any tips, feel free to comment, and if I wasn’t clear enough let me now.

Thank you very much for your time!

--

--

Luis Gustavo

Java Developer during the day, JavaScript enthusiast during the night.