3.4 Injectable Container Types

In addition to being able to inject beans, Micronaut natively supports injecting the following types:

Table 1. Injectable Container Types
TypeDescriptionExample

java.util.Optional

An Optional of a bean. empty() is injected if the bean doesn’t exist

Optional<Engine>

java.lang.Collection

An Collection or subtype of Collection (e.g. List, Set, etc.)

Collection<Engine>

java.util.stream.Stream

A lazy Stream of beans

Stream<Engine>

Array

A native array of beans of a given type

Engine[]

Provider

A javax.inject.Provider if a circular dependency requires it, or to instantiate a prototype for each get call.

Provider<Engine>

Provider

A jakarta.inject.Provider if a circular dependency requires it or to instantiate a prototype for each get call.

Provider<Engine>

BeanProvider

A io.micronaut.context.BeanProvider if a circular dependency requires it or to instantiate a prototype for each get call.

BeanProvider<Engine>

There are 3 different provider types supported, however the BeanProvider is the one we suggest to use.

When injecting a java.lang.Collection, or java.util.stream.Stream, Array of beans into a bean matching the injection type, then the owning bean will not be be a member of the injected collection. A common pattern demonstrating this is aggregation. For example:

  1. @Singleton
  2. class AggregateEngine implements Engine {
  3. @Inject
  4. List<Engine> engines;
  5. @Override
  6. public void start() {
  7. engines.forEach(Engine::start);
  8. }
  9. }

In this example, the injected member variable engines will not contain an instance of AggregateEngine

A prototype bean will have one instance created per place the bean is injected. When a prototype bean is injected as a provider, each call to get() creates a new instance.

Collection Ordering

When injecting a collection of beans, they are not ordered by default. Implement the Ordered interface to inject an ordered collection. If the requested bean type does not implement Ordered, Micronaut searches for the @Order annotation on beans.

The @Order annotation is especially useful for ordering beans created by factories where the bean type is a class in a third-party library. In this example, both LowRateLimit and HighRateLimit implement the RateLimit interface.

Factory with @Order

  1. import io.micronaut.context.annotation.Factory;
  2. import io.micronaut.core.annotation.Order;
  3. import jakarta.inject.Singleton;
  4. import java.time.Duration;
  5. @Factory
  6. public class RateLimitsFactory {
  7. @Singleton
  8. @Order(20)
  9. LowRateLimit rateLimit2() {
  10. return new LowRateLimit(Duration.ofMinutes(50), 100);
  11. }
  12. @Singleton
  13. @Order(10)
  14. HighRateLimit rateLimit1() {
  15. return new HighRateLimit(Duration.ofMinutes(50), 1000);
  16. }
  17. }

Factory with @Order

  1. import io.micronaut.context.annotation.Factory
  2. import io.micronaut.core.annotation.Order
  3. import jakarta.inject.Singleton
  4. import java.time.Duration
  5. @Factory
  6. class RateLimitsFactory {
  7. @Singleton
  8. @Order(20)
  9. LowRateLimit rateLimit2() {
  10. new LowRateLimit(Duration.ofMinutes(50), 100);
  11. }
  12. @Singleton
  13. @Order(10)
  14. HighRateLimit rateLimit1() {
  15. new HighRateLimit(Duration.ofMinutes(50), 1000);
  16. }
  17. }

Factory with @Order

  1. import io.micronaut.context.annotation.Factory
  2. import io.micronaut.core.annotation.Order
  3. import java.time.Duration
  4. import jakarta.inject.Singleton
  5. @Factory
  6. class RateLimitsFactory {
  7. @Singleton
  8. @Order(20)
  9. fun rateLimit2(): LowRateLimit {
  10. return LowRateLimit(Duration.ofMinutes(50), 100)
  11. }
  12. @Singleton
  13. @Order(10)
  14. fun rateLimit1(): HighRateLimit {
  15. return HighRateLimit(Duration.ofMinutes(50), 1000)
  16. }
  17. }

When a collection of RateLimit beans are requested from the context, they are returned in ascending order based on the value in the annotation.

Injecting a Bean by Order

When injecting a single instance of a bean the @Order annotation can also be used to define which bean has the highest precedence and hence should be injected.

The Ordered interface is not taken into account when selecting a single instance as this would require instantiating the bean to resolve the order.