4.6 Using @EachProperty to Drive Configuration

The @ConfigurationProperties annotation is great for a single configuration class, but sometimes you want multiple instances each with their own distinct configuration. That is where EachProperty comes in.

The @EachProperty annotation will create a ConfigurationProperties bean for each sub-property within the given property. As an example consider the following class:

Using @EachProperty

  1. import io.micronaut.context.annotation.Parameter;
  2. import io.micronaut.context.annotation.EachProperty;
  3. @EachProperty("test.datasource") (1)
  4. public class DataSourceConfiguration {
  5. private final String name;
  6. private URI url = new URI("localhost");
  7. public DataSourceConfiguration(@Parameter String name) (2)
  8. throws URISyntaxException {
  9. this.name = name;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public URI getUrl() { (3)
  15. return url;
  16. }
  17. public void setUrl(URI url) {
  18. this.url = url;
  19. }
  20. }

Using @EachProperty

  1. @EachProperty("test.datasource")
  2. (1)
  3. class DataSourceConfiguration {
  4. final String name
  5. URI url = new URI("localhost")
  6. DataSourceConfiguration(@Parameter String name) (2)
  7. throws URISyntaxException {
  8. this.name = name
  9. }
  10. }

Using @EachProperty

  1. @EachProperty("test.datasource") (1)
  2. class DataSourceConfiguration (2)
  3. @Throws(URISyntaxException::class)
  4. constructor(@param:Parameter val name: String) {
  5. (3)
  6. var url = URI("localhost")
  7. }
1The @EachProperty annotation defines the property name that should be handled.
2The @Parameter annotation can be used to inject the name of the sub-property that defines the name of the bean (which is also the bean qualifier)
3Each property of the bean is bound to configuration.

The above DataSourceConfiguration defines a url property to configure one or many hypothetical data sources of some sort. The URLs themselves can be configured using any of the PropertySource instances evaluated to Micronaut:

Providing Configuration to @EachProperty

  1. ApplicationContext applicationContext = ApplicationContext.run(PropertySource.of(
  2. "test",
  3. CollectionUtils.mapOf(
  4. "test.datasource.one.url", "jdbc:mysql://localhost/one",
  5. "test.datasource.two.url", "jdbc:mysql://localhost/two")
  6. ));

Providing Configuration to @EachProperty

  1. ApplicationContext applicationContext = ApplicationContext.run(PropertySource.of(
  2. "test",
  3. [
  4. "test.datasource.one.url": "jdbc:mysql://localhost/one",
  5. "test.datasource.two.url": "jdbc:mysql://localhost/two"
  6. ]
  7. ))

Providing Configuration to @EachProperty

  1. val applicationContext = ApplicationContext.run(PropertySource.of(
  2. "test",
  3. mapOf(
  4. "test.datasource.one.url" to "jdbc:mysql://localhost/one",
  5. "test.datasource.two.url" to "jdbc:mysql://localhost/two"
  6. )
  7. ))

In the above example two data sources (called one and two) are defined under the test.datasource prefix defined earlier in the @EachProperty annotation. Each of these configuration entries triggers the creation of a new DataSourceConfiguration bean such that the following test succeeds:

Evaluating Beans Built by @EachProperty

  1. Collection<DataSourceConfiguration> beansOfType = applicationContext.getBeansOfType(DataSourceConfiguration.class);
  2. assertEquals(2, beansOfType.size()); (1)
  3. DataSourceConfiguration firstConfig = applicationContext.getBean(
  4. DataSourceConfiguration.class,
  5. Qualifiers.byName("one") (2)
  6. );
  7. assertEquals(
  8. new URI("jdbc:mysql://localhost/one"),
  9. firstConfig.getUrl()
  10. );

Evaluating Beans Built by @EachProperty

  1. when:
  2. Collection<DataSourceConfiguration> beansOfType = applicationContext.getBeansOfType(DataSourceConfiguration.class)
  3. assertEquals(2, beansOfType.size()) (1)
  4. DataSourceConfiguration firstConfig = applicationContext.getBean(
  5. DataSourceConfiguration.class,
  6. Qualifiers.byName("one") (2)
  7. )
  8. then:
  9. new URI("jdbc:mysql://localhost/one") == firstConfig.getUrl()

Evaluating Beans Built by @EachProperty

  1. val beansOfType = applicationContext.getBeansOfType(DataSourceConfiguration::class.java)
  2. assertEquals(2, beansOfType.size.toLong()) (1)
  3. val firstConfig = applicationContext.getBean(
  4. DataSourceConfiguration::class.java,
  5. Qualifiers.byName("one") (2)
  6. )
  7. assertEquals(
  8. URI("jdbc:mysql://localhost/one"),
  9. firstConfig.url
  10. )
1All beans of type DataSourceConfiguration can be retrieved using getBeansOfType
2Individual beans can be achieved by using the byName qualifier.