24.7 Type-safe Configuration Properties

Using the @Value("${property}") annotation to inject configuration properties can sometimes be cumbersome, especially if you are working with multiple properties or your data is hierarchical in nature. Spring Boot provides an alternative method of working with properties that allows strongly typed beans to govern and validate the configuration of your application. For example:

_@ConfigurationProperties(prefix="connection")_
public class ConnectionProperties {

    private String username;

    private InetAddress remoteAddress;

    // ... getters and setters

}
[Note] Note
The getters and setters are advisable, since binding is via standard Java Beans property descriptors, just like in Spring MVC. They are mandatory for immutable types or those that are directly coercible from String. As long as they are initialized, maps, collections, and arrays need a getter but not necessarily a setter since they can be mutated by the binder. If there is a setter, Maps, collections, and arrays can be created. Maps and collections can be expanded with only a getter, whereas arrays require a setter. Nested POJO properties can also be created (so a setter is not mandatory) if they have a default constructor, or a constructor accepting a single value that can be coerced from String. Some people use Project Lombok to add getters and setters automatically.
[Tip] Tip
See also the differences between @Value and @ConfigurationProperties.

You also need to list the properties classes to register in the @EnableConfigurationProperties annotation:

_@Configuration_
_@EnableConfigurationProperties(ConnectionProperties.class)_
public class MyConfiguration {
}
[Note] Note
When @ConfigurationProperties bean is registered that way, the bean will have a conventional name: &lt;prefix&gt;-&lt;fqn&gt;, where &lt;prefix&gt; is the environment key prefix specified in the @ConfigurationProperties annotation and <fqn> the fully qualified name of the bean. If the annotation does not provide any prefix, only the fully qualified name of the bean is used.

Even if the configuration above will create a regular bean for ConnectionProperties, we recommend that @ConfigurationProperties only deal with the environment and in particular does not inject other beans from the context. Having said that, The @EnableConfigurationProperties annotation is also automatically applied to your project so that any existing bean annotated with @ConfigurationProperties will be configured from the Environment properties. You could shortcut MyConfiguration above by making sure ConnectionProperties is a already a bean:

_@Component_
_@ConfigurationProperties(prefix="connection")_
public class ConnectionProperties {

    // ... getters and setters

}

This style of configuration works particularly well with the SpringApplication external YAML configuration:

# application.yml

connection:
 username: admin
 remoteAddress: 192.168.1.1

# additional configuration as required

To work with @ConfigurationProperties beans you can just inject them in the same way as any other bean.

_@Service_
public class MyService {

    private final ConnectionProperties connection;

    _@Autowired_
    public MyService(ConnectionProperties connection) {
        this.connection = connection;
    }

     //...

    _@PostConstruct_
    public void openConnection() {
        Server server = new Server();
        this.connection.configure(server);
    }

}
[Tip] Tip
Using @ConfigurationProperties also allows you to generate meta-data files that can be used by IDEs. See the Appendix B, Configuration meta-data appendix for details.

24.7.1 Third-party configuration

As well as using @ConfigurationProperties to annotate a class, you can also use it on public @Bean methods. This can be particularly useful when you want to bind properties to third-party components that are outside of your control.

To configure a bean from the Environment properties, add @ConfigurationProperties to its bean registration:

_@ConfigurationProperties(prefix = "foo")_
_@Bean_
public FooComponent fooComponent() {
    ...
}

Any property defined with the foo prefix will be mapped onto that FooComponent bean in a similar manner as the ConnectionProperties example above.

24.7.2 Relaxed binding

Spring Boot uses some relaxed rules for binding Environment properties to @ConfigurationProperties beans, so there doesn’t need to be an exact match between the Environment property name and the bean property name. Common examples where this is useful include dashed separated (e.g. context-path binds to contextPath), and capitalized (e.g. PORT binds to port) environment properties.

For example, given the following @ConfigurationProperties class:

_@ConfigurationProperties(prefix="person")_
public class OwnerProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

The following properties names can all be used:

Table 24.1. relaxed binding

Property Note
person.firstName Standard camel case syntax.
person.first-name Dashed notation, recommended for use in .properties and .yml files.
person.first_name Underscore notation, alternative format for use in .properties and .yml files.
PERSON_FIRST_NAME Upper case format. Recommended when using a system environment variables.

24.7.3 Properties conversion

Spring will attempt to coerce the external application properties to the right type when it binds to the @ConfigurationProperties beans. If you need custom type conversion you can provide a ConversionService bean (with bean id conversionService) or custom property editors (via a CustomEditorConfigurer bean) or custom Converters (with bean definitions annotated as @ConfigurationPropertiesBinding).

[Note] Note
As this bean is requested very early during the application lifecycle, make sure to limit the dependencies that your ConversionService is using. Typically, any dependency that you require may not be fully initialized at creation time. You may want to rename your custom ConversionService if it’s not required for configuration keys coercion and only rely on custom converters qualified with @ConfigurationPropertiesBinding.

24.7.4 @ConfigurationProperties Validation

Spring Boot will attempt to validate external configuration, by default using JSR-303 (if it is on the classpath). You can simply add JSR-303 javax.validation constraint annotations to your @ConfigurationProperties class:

_@ConfigurationProperties(prefix="connection")_
public class ConnectionProperties {

    _@NotNull_
    private InetAddress remoteAddress;

    // ... getters and setters

}

In order to validate values of nested properties, you must annotate the associated field as @Valid to trigger its validation. For example, building upon the above ConnectionProperties example:

_@ConfigurationProperties(prefix="connection")_
public class ConnectionProperties {

    _@NotNull_
    _@Valid_
    private RemoteAddress remoteAddress;

    // ... getters and setters

    public static class RemoteAddress {

        _@NotEmpty_
        public String hostname;

        // ... getters and setters

    }

}

You can also add a custom Spring Validator by creating a bean definition called configurationPropertiesValidator. The @Bean method should be declared static. The configuration properties validator is created very early in the application’s lifecycle and declaring the @Bean method as static allows the bean to be created without having to instantiate the @Configuration class. This avoids any problems that may be caused by early instantiation. There is a property validation sample so you can see how to set things up.

[Tip] Tip
The spring-boot-actuator module includes an endpoint that exposes all @ConfigurationProperties beans. Simply point your web browser to /configprops or use the equivalent JMX endpoint. See the Production ready features. section for details.

24.7.5 @ConfigurationProperties vs. @Value

@Value is a core container feature and it does not provide the same features as type-safe Configuration Properties. The table below summarizes the features that are supported by @ConfigurationProperties and @Value:

Feature @ConfigurationProperties @Value
Relaxed binding Yes No
Meta-data support Yes No
SpEL evaluation No Yes

If you define a set of configuration keys for your own components, we recommend you to group them in a POJO annotated with @ConfigurationProperties. Please also be aware that since @Value does not support relaxed binding, it isn’t a great candidate if you need to provide the value using environment variables.

Finally, while you can write a SpEL expression in @Value, such expressions are not processed from Application property files.

results matching ""

    No results matching ""