Micronaut Dependency Injection - The stand-alone Setup
In this post, let's explore how to use Micronaut as the Dependency Injection container in a stand-alone Java application.
Let's start by creating a stand-alone Java application. I make use of the initialisers provided by Gradle (gradle init
command). The application structure looks as follows.
➜ microdemo tree
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── nareshak
│ │ └── demo
│ │ └── App.java
│ └── resources
└── test
├── java
│ └── com
│ └── nareshak
│ └── demo
│ └── AppTest.java
└── resources
15 directories, 8 files
Let's open the file build.gradle
and add the necessary dependencies for Micronaut DI to work. After adding the Micronaut dependencies, build.gradle
will be as follows.
plugins {
id 'java'
id 'application'
}
repositories {
jcenter()
}
dependencies {
annotationProcessor(platform("io.micronaut:micronaut-bom:2.0.2")) // D1
annotationProcessor("io.micronaut:micronaut-inject-java") // D2
implementation(platform("io.micronaut:micronaut-bom:2.0.2")) // D3
implementation("io.micronaut:micronaut-inject") // D4
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.2'
}
application {
mainClassName = 'com.nareshak.demo.App'
}
test {
useJUnitPlatform()
}
I have commented on the newly added dependencies with 'D1' to 'D4'.
D1
D1 adds a BOM dependency in the 'annotationProcessor' scope. This line is responsible for bringing the compatible versions of transitive dependencies into the scope.
D2
D2 brings the dependency micronaut-inject-java
along with its transitive dependencies into the 'annotationProcessor' scope. This dependency ensures that the compiler invokes the code from the corresponding jar file before compiling our application code. The dependency tree for micronaut-inject-java
is as follows (obtained through dependencies
task).
\--- io.micronaut:micronaut-inject-java -> 2.0.2
+--- org.slf4j:slf4j-api:1.7.26
+--- io.micronaut:micronaut-inject:2.0.2
| +--- org.slf4j:slf4j-api:1.7.26
| +--- javax.annotation:javax.annotation-api:1.3.2
| +--- javax.inject:javax.inject:1
| +--- io.micronaut:micronaut-core:2.0.2
| | +--- org.slf4j:slf4j-api:1.7.26
| | +--- org.reactivestreams:reactive-streams:1.0.3
| | \--- com.github.spotbugs:spotbugs-annotations:4.0.3
| | \--- com.google.code.findbugs:jsr305:3.0.2
| \--- org.yaml:snakeyaml:1.26
\--- io.micronaut:micronaut-aop:2.0.2
+--- org.slf4j:slf4j-api:1.7.26
+--- io.micronaut:micronaut-inject:2.0.2 (*)
\--- io.micronaut:micronaut-core:2.0.2 (*)
D3
Similar to D1 but this BOM is for the 'implementation' scope.
D4
This line adds 'micronaut-inject' jar and its transitive dependencies to the 'implementation' scope. We will use classes and interfaces from this jar to create and retrieve instances of classes to be injected.
\--- io.micronaut:micronaut-inject -> 2.0.2
+--- org.slf4j:slf4j-api:1.7.26
+--- javax.annotation:javax.annotation-api:1.3.2
+--- javax.inject:javax.inject:1
+--- io.micronaut:micronaut-core:2.0.2
| +--- org.slf4j:slf4j-api:1.7.26
| +--- org.reactivestreams:reactive-streams:1.0.3
| \--- com.github.spotbugs:spotbugs-annotations:4.0.3
| \--- com.google.code.findbugs:jsr305:3.0.2
\--- org.yaml:snakeyaml:1.26
Let's go ahead and create a class Greeter
as follows.
package com.nareshak.demo;
import javax.inject.Singleton;
@Singleton
public class Greeter {
}
We want the class Greeter
to be singleton - meaning once instance of the class should exist.
Let's try to get the instance of Greeter
through Micronaut as follows.
package com.nareshak.demo;
import io.micronaut.context.ApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext context = ApplicationContext.run();
System.out.println(context.getBean(Greeter.class)); // com.nareshak.demo.Greeter@60611244
System.out.println(context.getBean(Greeter.class)); // com.nareshak.demo.Greeter@60611244
}
}
The entry point to Micronaut dependency injection in the above code is ApplicationContext
. We can get an instance of it by invoking the static method run
. Then we invoke the getBean
method by passing the class whose instance we need. We observe that we receive the same instance of Greeter
on both the invocations of getBean
adhering to the singleton property.
Micronaut version used: 2.0.2