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 | |
---|---|
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 | |
---|---|
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 | |
---|---|
When @ConfigurationProperties bean is registered that way, the bean will have a conventional name: <prefix>-<fqn> , where <prefix> 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 | |
---|---|
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 | |
---|---|
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 | |
---|---|
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.