When you start using frameworks like Micronaut, you often hear the term Dependency Injection (DI).
For beginners, this term may sound complicated. But don’t worry — in this post, we’ll break it down into simple language and see how Dependency Injection works in Micronaut with easy examples.
By the end, you’ll feel very comfortable with this core concept.

What is Dependency Injection? (In Very Simple Words)
First, let’s understand what a dependency is:
A dependency is any object that your class needs to work.
For example:
- Your
Car
class needs anEngine
object. - Your
OrderService
needs aPaymentService
to process payments.
Normally, you would write code like this:
1 2 3 4 5 6 |
public class Car { private Engine engine = new Engine(); } |
Here, the Car
creates its own Engine
.
The Problem
- Your classes are tightly connected.
- It’s harder to test.
- You can’t easily swap different engines.
The Solution: Dependency Injection
Instead of creating the dependencies yourself, you inject them from outside.
Example:
1 2 3 4 5 6 7 8 9 10 |
public class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } } |
Now, whoever creates Car
will provide the Engine
.
This is Dependency Injection.
✅ Simple takeaway:
Dependency Injection means giving objects what they need instead of letting them create things themselves.
Why Use Dependency Injection?
- Easier to maintain code.
- Easier to test.
- More flexible and modular.
- Promotes clean design.
How Micronaut Helps With Dependency Injection
Without frameworks like Micronaut, you would have to manually inject everything. This can become very painful in large projects.
Micronaut does all the heavy lifting for you:
- It creates and injects objects automatically.
- It uses annotations to know what to inject.
- It works at compile-time (more on this later), making it fast and efficient.
Types of Dependency Injection in Micronaut
Micronaut supports three common ways to inject dependencies:
Type | Example |
---|---|
Constructor Injection | Most recommended |
Field Injection | Simplest syntax |
Method Injection | Less common |
1️⃣ Constructor Injection (Recommended)
Here’s a full example in simple language:
Create a Service
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package com.kscodes.micronaut; import jakarta.inject.Singleton; @Singleton public class GreetingService { public String greet(String name) { return "Hello, " + name + "!"; } } |
@Singleton
: Tells Micronaut to create only one instance of this class and manage it.
Inject into Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.kscodes.micronaut; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller("/greet") public class GreetingController { private final GreetingService greetingService; public GreetingController(GreetingService greetingService) { this.greetingService = greetingService; } @Get("/{name}") public String greet(String name) { return greetingService.greet(name); } } |
✅ Micronaut automatically creates GreetingService
and injects it into GreetingController
.
2️⃣ Field Injection
You can also inject directly into fields.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.kscodes.micronaut; import jakarta.inject.Inject; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller("/greet") public class GreetingController { @Inject GreetingService greetingService; @Get("/{name}") public String greet(String name) { return greetingService.greet(name); } } |
✅ Works fine, but constructor injection is often better for testing and design.
3️⃣ Method Injection
You can also inject through methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.kscodes.micronaut; import jakarta.inject.Inject; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller("/greet") public class GreetingController { private GreetingService greetingService; @Inject public void setGreetingService(GreetingService greetingService) { this.greetingService = greetingService; } @Get("/{name}") public String greet(String name) { return greetingService.greet(name); } } |
Behind the Scenes — How Micronaut DI Works
Most frameworks like Spring Boot use runtime reflection to analyze your code when the application starts.
👉 But Micronaut does this at compile-time.
What does this mean?
- Micronaut analyzes your code when you build it.
- It creates all the wiring (called “bean definitions”) ahead of time.
- At runtime, everything is ready to go → faster startup, less memory usage.
✅ Simple takeaway:
Micronaut is faster because it does the hard work early, not at runtime.
Common DI Annotations in Micronaut
Annotation | Purpose |
---|---|
@Singleton | Tells Micronaut to create only one instance of a class |
@Inject | Marks where to inject a dependency |
@Controller | Marks a class that handles HTTP requests |
@Value | Injects configuration values |
Bonus: Injecting Configuration
You can even inject values from your configuration file!
application.yml
1 2 3 4 5 |
greeting: message: Welcome to Micronaut! |
Inject Config Value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package com.kscodes.micronaut; import io.micronaut.context.annotation.Value; import jakarta.inject.Singleton; @Singleton public class ConfigService { @Value("${greeting.message}") private String message; public String getMessage() { return message; } } |
✅ Micronaut reads values from application.yml
and injects them into your class.
Why Beginners Love DI in Micronaut
- ✅ No need to write complex factory code.
- ✅ Less boilerplate.
- ✅ Easy to test.
- ✅ Fast performance.
- ✅ Extremely simple once you understand it.
Recap Table
Concept | Explanation |
---|---|
What is DI? | Giving objects what they need |
Micronaut DI | Automatic, compile-time |
Recommended Style | Constructor injection |
Main Annotation | @Singleton , @Inject |
Benefit | Fast, clean, testable code |
Conclusion
Dependency Injection is like having an assistant who automatically hands you the tools you need exactly when you need them.
Micronaut makes this incredibly easy, fast, and efficient — even for complete beginners.
Once you understand DI, you unlock one of the biggest powers of modern Java frameworks.