There are two ways to define immutable configuration. The preferred way is to define an interface that is annotated with . For example:
@ConfigurationProperties Example
@ConfigurationProperties Example
import io.micronaut.core.bind.annotation.Bindable
import javax.validation.constraints.*
@ConfigurationProperties("my.engine") (1)
interface EngineConfig {
@Bindable(defaultValue = "Ford") (2)
@NotBlank (3)
String getManufacturer()
@Min(1L)
int getCylinders()
@NotNull
CrankShaft getCrankShaft() (4)
@ConfigurationProperties("crank-shaft")
static interface CrankShaft { (5)
Optional<Double> getRodLength() (6)
}
}
@ConfigurationProperties Example
import io.micronaut.context.annotation.ConfigurationProperties
import io.micronaut.core.bind.annotation.Bindable
import javax.validation.constraints.*
import java.util.Optional
@ConfigurationProperties("my.engine") (1)
interface EngineConfig {
@get:Bindable(defaultValue = "Ford") (2)
@get:NotBlank (3)
val manufacturer: String
@get:Min(1L)
val cylinders: Int
@get:NotNull
val crankShaft: CrankShaft (4)
@ConfigurationProperties("crank-shaft")
interface CrankShaft { (5)
val rodLength: Double? (6)
}
In this case what Micronaut does is provide a compilation time implementation that delegates all getters to call the method of the Environment interface.
This has the advantage that if the application’s configuration is (for example by invoking the /refresh
endpoint) then the injected interface will automatically see the new values.
An alternative way to implement immutable configuration is to define a class and use the @ConfigurationInject annotation on a constructor of a or @EachProperty bean.
@ConfigurationProperties Example
@ConfigurationProperties Example
import io.micronaut.context.annotation.*
import io.micronaut.core.bind.annotation.Bindable
import javax.annotation.Nullable
import javax.validation.constraints.Min
import javax.validation.constraints.NotBlank
import javax.validation.constraints.NotNull
@ConfigurationProperties("my.engine") (1)
class EngineConfig {
private final String manufacturer
private final int cylinders
private final CrankShaft crankShaft
@ConfigurationInject (2)
EngineConfig(
@Bindable(defaultValue = "Ford") @NotBlank String manufacturer, (3)
@Min(1L) int cylinders, (4)
@NotNull CrankShaft crankShaft) {
this.manufacturer = manufacturer
this.cylinders = cylinders
this.crankShaft = crankShaft
}
String getManufacturer() {
return manufacturer
}
int getCylinders() {
return cylinders
}
CrankShaft getCrankShaft() {
return crankShaft
}
@ConfigurationProperties("crank-shaft")
static class CrankShaft { (5)
private final Double rodLength (6)
@ConfigurationInject
CrankShaft(@Nullable Double rodLength) {
this.rodLength = rodLength
}
}
}
}
@ConfigurationProperties Example
import io.micronaut.context.annotation.*
import io.micronaut.core.bind.annotation.Bindable
import javax.validation.constraints.*
import java.util.Optional
@ConfigurationProperties("my.engine") (1)
data class EngineConfig @ConfigurationInject (2)
constructor(
@Bindable(defaultValue = "Ford") @NotBlank (3)
val manufacturer: String,
@Min(1L) (4)
val cylinders: Int,
@NotNull val crankShaft: CrankShaft) {
@ConfigurationProperties("crank-shaft")
data class CrankShaft @ConfigurationInject
constructor((5)
private val rodLength: Double? (6)
) {
fun getRodLength(): Optional<Double> {
return Optional.ofNullable(rodLength)
}
}
}
The annotation provides a hint to Micronaut to prioritize binding values from configuration instead of injecting beans.
There are a few exceptions to this rule. Micronaut will not perform configuration binding for a parameter if one of these conditions is met:
The parameter is annotated with
@Value
(explicit binding)The parameter is annotated with
@Property
(explicit binding)The type of the parameter is annotated with a bean scope (such as
@Singleton
)
Once you have prepared a type safe configuration it can simply be injected into your objects like any other bean:
Configuration values can then be supplied when running the application. For example:
Supply Configuration
Supply Configuration
ApplicationContext applicationContext = ApplicationContext.run(
"my.engine.cylinders": "8",
"my.engine.crank-shaft.rod-length": "7.0"
)
Vehicle vehicle = applicationContext.getBean(Vehicle.class)
System.out.println(vehicle.start())
Supply Configuration
val map = mapOf(
"my.engine.cylinders" to "8",
"my.engine.crank-shaft.rod-length" to "7.0"
)
val applicationContext = ApplicationContext.run(map)
The above example prints: "Ford Engine Starting V8 [rodLength=7B.0]"