4.2 Externalized Configuration with PropertySources

Additional PropertySource instances can be added to the environment prior to initializing the ApplicationContext.

Initializing the Environment

  1. ApplicationContext applicationContext = ApplicationContext.run(
  2. PropertySource.of(
  3. "test",
  4. CollectionUtils.mapOf(
  5. "micronaut.server.host", "foo",
  6. "micronaut.server.port", 8080
  7. )
  8. ),
  9. "test", "android");
  10. Environment environment = applicationContext.getEnvironment();
  11. assertEquals(
  12. "foo",
  13. environment.getProperty("micronaut.server.host", String.class).orElse("localhost")
  14. );

Initializing the Environment

  1. when:
  2. ApplicationContext applicationContext = ApplicationContext.run(
  3. PropertySource.of(
  4. "test",
  5. [
  6. "micronaut.server.host": "foo",
  7. "micronaut.server.port": 8080
  8. ]
  9. ),
  10. "test", "android")
  11. Environment environment = applicationContext.getEnvironment()
  12. then:
  13. "foo" == environment.getProperty("micronaut.server.host", String.class).orElse("localhost")

Initializing the Environment

  1. val applicationContext = ApplicationContext.run(
  2. PropertySource.of(
  3. "test",
  4. mapOf(
  5. "micronaut.server.host" to "foo",
  6. "micronaut.server.port" to 8080
  7. )
  8. ),
  9. "test", "android"
  10. )
  11. val environment = applicationContext.environment
  12. assertEquals(
  13. "foo",
  14. environment.getProperty("micronaut.server.host", String::class.java).orElse("localhost")
  15. )

The PropertySource.of method can be used to create a PropertySource from a map of values.

Alternatively one can register a PropertySourceLoader by creating a META-INF/services/io.micronaut.context.env.PropertySourceLoader file containing a reference to the class name of the PropertySourceLoader.

Included PropertySource Loaders

Micronaut by default contains PropertySourceLoader implementations that load properties from the given locations and priority:

  1. Command line arguments

  2. Properties from SPRING_APPLICATION_JSON (for Spring compatibility)

  3. Properties from MICRONAUT_APPLICATION_JSON

  4. Java System Properties

  5. OS environment variables

  6. Configuration files loaded in order from the system property ‘micronaut.config.files’ or the environment variable MICRONAUT_CONFIG_FILES. The value can be a comma-separated list of paths with the last file having precedence. The files can be referenced from the file system as a path, or the classpath with a classpath: prefix.

  7. Environment-specific properties from application-{environment}.{extension}

  8. Application-specific properties from application.{extension}

.properties, .json, .yml are supported out of the box. For Groovy users .groovy is supported as well.

Supplying Configuration via Command Line

Configuration can be supplied at the command line using Gradle or our Maven plugin. For example:

Gradle

  1. $ ./gradlew run --args="-endpoints.health.enabled=true -config.property=test"

Maven

  1. $ ./mvnw mn:run -Dmn.appArgs="-endpoints.health.enabled=true -config.property=test"

For the configuration to be a part of the context, the args from the main method must be passed to the context builder. For example:

  1. import io.micronaut.runtime.Micronaut;
  2. public class Application {
  3. public static void main(String[] args) {
  4. Micronaut.run(Application.class, args); // passing args
  5. }
  6. }

Property Value Placeholders

Micronaut includes a property placeholder syntax to reference configuration properties both within configuration values and with any Micronaut annotation. See @Value and the section on Configuration Injection.

Programmatic usage is also possible via the PropertyPlaceholderResolver interface.

The basic syntax is to wrap a reference to a property in ${…​}. For example in application.yml:

Defining Property Placeholders

  1. myapp:
  2. endpoint: http://${micronaut.server.host}:${micronaut.server.port}/foo

The above example embeds references to the micronaut.server.host and micronaut.server.port properties.

You can specify default values by defining a value after the : character. For example:

Using Default Values

  1. myapp:
  2. endpoint: http://${micronaut.server.host:localhost}:${micronaut.server.port:8080}/foo

The above example defaults to localhost and port 8080 if no value is found (rather than throwing an exception). Note that if the default value contains a : character, you must escape it using backticks:

Using Backticks

  1. myapp:
  2. endpoint: ${server.address:`http://localhost:8080`}/foo

The above example looks for a server.address property and defaults to [http://localhost:8080](http://localhost:8080). This default value is escaped with backticks since it has a : character.

Property Value Binding

Note that these property references should be in kebab case (lowercase and hyphen-separated) when placing references in code or in placeholder values. For example, use micronaut.server.default-charset and not micronaut.server.defaultCharset.

Micronaut still allows specifying the latter in configuration, but normalizes the properties into kebab case form to optimize memory consumption and reduce complexity when resolving properties. The following table summarizes how properties are normalized from different sources:

Table 1. Property Value Normalization
Configuration ValueResulting PropertiesProperty Source

myApp.myStuff

my-app.my-stuff

Properties, YAML etc.

my-app.myStuff

my-app.my-stuff

Properties, YAML etc.

myApp.my-stuff

my-app.my-stuff

Properties, YAML etc.

MYAPP_MYSTUFF

myapp.mystuff, myapp-mystuff

Environment Variable

MY_APP_MY_STUFF

my.app.my.stuff, my.app.my-stuff, my.app-my.stuff, my.app-my-stuff, my-app.my.stuff, my-app.my-stuff, my-app-my.stuff, my-app-my-stuff

Environment Variable

Environment variables are treated specially to allow more flexibility. Note that there is no way to reference an environment variable with camel-case.

Because the number of properties generated is exponential based on the number of _ characters in an environment variable, it is recommended to refine which, if any, environment variables are included in configuration if the number of environment variables with multiple underscores is high.

To control how environment properties participate in configuration, call the respective methods on the Micronaut builder.

Application class

  1. import io.micronaut.runtime.Micronaut;
  2. public class Application {
  3. public static void main(String[] args) {
  4. Micronaut.build(args)
  5. .mainClass(Application.class)
  6. .environmentPropertySource(false)
  7. //or
  8. .environmentVariableIncludes("THIS_ENV_ONLY")
  9. //or
  10. .environmentVariableExcludes("EXCLUDED_ENV")
  11. .start();
  12. }
  13. }

Application class

  1. import io.micronaut.runtime.Micronaut
  2. class Application {
  3. static void main(String[] args) {
  4. Micronaut.build()
  5. .mainClass(Application)
  6. .environmentPropertySource(false)
  7. //or
  8. .environmentVariableIncludes("THIS_ENV_ONLY")
  9. //or
  10. .environmentVariableExcludes("EXCLUDED_ENV")
  11. .start()
  12. }
  13. }

Application class

  1. import io.micronaut.runtime.Micronaut
  2. object Application {
  3. @JvmStatic
  4. fun main(args: Array<String>) {
  5. Micronaut.build(null)
  6. .mainClass(Application::class.java)
  7. .environmentPropertySource(false)
  8. //or
  9. .environmentVariableIncludes("THIS_ENV_ONLY")
  10. //or
  11. .environmentVariableExcludes("EXCLUDED_ENV")
  12. .start()
  13. }
  14. }
The configuration above does not have any impact on property placeholders. It is still possible to reference an environment variable in a placeholder regardless of whether environment configuration is disabled, or even if the specific property is explicitly excluded.

Using Random Properties

You can use random values by using the following properties. These can be used in configuration files as variables like the following.

  1. micronaut:
  2. application:
  3. name: myapplication
  4. instance:
  5. id: ${random.shortuuid}
Table 2. Random Values
PropertyValue

random.port

An available random port number

random.int

Random int

random.integer

Random int

random.long

Random long

random.float

Random float

random.shortuuid

Random UUID of only 10 chars in length (Note: As this isn’t full UUID, collision COULD occur)

random.uuid

Random UUID with dashes

random.uuid2

Random UUID without dashes

The random.int, random.integer, random.long and random.float properties supports a range suffix whose syntax is one of as follows:

  • (max) where max is an exclusive value

  • [min,max] where min being inclusive and max being exclusive values.

  1. instance:
  2. id: ${random.int[5,10]}
  3. count: ${random.int(5)}
The range could vary from negative to positive as well.

Fail Fast Property Injection

For beans that inject required properties, the injection and potential failure will not occur until the bean is requested. To verify at startup that the properties exist and can be injected, the bean can be annotated with @Context. Context-scoped beans are injected at startup, and startup fails if any required properties are missing or cannot be converted to the required type.

It is recommended to use this feature sparingly to ensure fast startup.

Controlling Log Levels with Properties

Log levels can be configured via properties defined in application.yml (and environment variables) with the logger.levels prefix:

  1. logger:
  2. levels:
  3. foo.bar: ERROR

The same configuration can be achieved by setting the environment variable LOGGER_LEVELS_FOO_BAR. Note that there is currently no way to set log levels for unconventional prefixes such as foo.barBaz.

Disabling a Logger with Properties

To disable a logger, you need to set the logger level to OFF:

  1. logger:
  2. levels:
  3. io.verbose.logger.who.CriedWolf: OFF (1)
  1. This will disable ALL logging for the class io.verbose.logger.who.CriedWolf

Note that the ability to control log levels via config is controlled via the LoggingSystem interface. Currently, Micronaut includes a single implementation that allows setting log levels for the Logback library. If you use another library, you should provide a bean that implements this interface.