|
|
|
@ -815,34 +815,95 @@ will contain _one_ `MyPojo` entry (with name "`my another name`" and description
|
|
|
|
|
[[boot-features-external-config-typesafe-configuration-properties]]
|
|
|
|
|
=== 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:
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@ConfigurationProperties(prefix="connection")
|
|
|
|
|
public class ConnectionProperties {
|
|
|
|
|
package com.example;
|
|
|
|
|
|
|
|
|
|
private String username;
|
|
|
|
|
import java.net.InetAddress;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
|
|
|
|
|
|
|
|
@ConfigurationProperties("foo")
|
|
|
|
|
public class FooProperties {
|
|
|
|
|
|
|
|
|
|
private boolean enabled;
|
|
|
|
|
|
|
|
|
|
private InetAddress remoteAddress;
|
|
|
|
|
|
|
|
|
|
// ... getters and setters
|
|
|
|
|
private final Security security = new Security();
|
|
|
|
|
|
|
|
|
|
public boolean isEnabled() { ... }
|
|
|
|
|
|
|
|
|
|
public void setEnabled(boolean enabled) { ... }
|
|
|
|
|
|
|
|
|
|
public InetAddress getRemoteAddress() { ... }
|
|
|
|
|
|
|
|
|
|
public void setRemoteAddress(InetAddress remoteAddress) { ... }
|
|
|
|
|
|
|
|
|
|
public Security getSecurity() { ... }
|
|
|
|
|
|
|
|
|
|
public static class Security {
|
|
|
|
|
|
|
|
|
|
private String username;
|
|
|
|
|
|
|
|
|
|
private String password;
|
|
|
|
|
|
|
|
|
|
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
|
|
|
|
|
|
|
|
|
|
public String getUsername() { ... }
|
|
|
|
|
|
|
|
|
|
public void setUsername(String username) { ... }
|
|
|
|
|
|
|
|
|
|
public String getPassword() { ... }
|
|
|
|
|
|
|
|
|
|
public void setPassword(String password) { ... }
|
|
|
|
|
|
|
|
|
|
public List<String> getRoles() { ... }
|
|
|
|
|
|
|
|
|
|
public void setRoles(List<String> roles) { ... }
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
The POJO above defines the following properties:
|
|
|
|
|
|
|
|
|
|
* `foo.enabled`, `false` by default
|
|
|
|
|
* `foo.remote-address`, with a type that can be coerced from `String`
|
|
|
|
|
* `foo.security.username`, with a nested "security" whose name is determined by the name
|
|
|
|
|
of the property. In particular the return type is not used at all there and could have
|
|
|
|
|
been `SecurityProperties`
|
|
|
|
|
* `foo.security.password`
|
|
|
|
|
* `foo.security.roles`, with a collection of `String`
|
|
|
|
|
|
|
|
|
|
[NOTE]
|
|
|
|
|
====
|
|
|
|
|
Getters and setters are usually mandatory, since binding is via standard Java Beans
|
|
|
|
|
property descriptors, just like in Spring MVC. There are cases where a setter may be
|
|
|
|
|
omitted:
|
|
|
|
|
|
|
|
|
|
* Maps, as long as they are initialized, need a getter but not necessarily a setter since
|
|
|
|
|
they can be mutated by the binder.
|
|
|
|
|
* Collections and arrays can be either accessed via an index (typically with YAML) or
|
|
|
|
|
using a single comma-separated value (properties). In the latter case, a setter is
|
|
|
|
|
mandatory. We recommend to always add a setter for such types. If you initialize a
|
|
|
|
|
collection, make sure it is not immutable (as in the example above)
|
|
|
|
|
* If nested POJO properties are initialized (like the `Security` field in the example
|
|
|
|
|
above), a setter is not required. If you want the binder to create the instance on-the-fly
|
|
|
|
|
using its default constructor, you will need a setter.
|
|
|
|
|
|
|
|
|
|
Some people use Project Lombok to add getters and setters automatically. Make sure that
|
|
|
|
|
Lombok doesn't generate any particular constructor for such type as it will be used
|
|
|
|
|
automatically by the container to instantiate the object.
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
TIP: See also the <<boot-features-external-config-vs-value,differences between `@Value`
|
|
|
|
|
and `@ConfigurationProperties`>>.
|
|
|
|
@ -853,7 +914,7 @@ You also need to list the properties classes to register in the
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@Configuration
|
|
|
|
|
@EnableConfigurationProperties(ConnectionProperties.class)
|
|
|
|
|
@EnableConfigurationProperties(FooProperties.class)
|
|
|
|
|
public class MyConfiguration {
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
@ -862,29 +923,28 @@ You also need to list the properties classes to register in the
|
|
|
|
|
====
|
|
|
|
|
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
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
The bean name in the example above will be `connection-com.example.ConnectionProperties`,
|
|
|
|
|
assuming that `ConnectionProperties` sits in the `com.example` package.
|
|
|
|
|
The bean name in the example above will be `foo-com.example.FooProperties`.
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
Even if the configuration above will create a regular bean for `ConnectionProperties`, we
|
|
|
|
|
Even if the configuration above will create a regular bean for `FooProperties`, 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:
|
|
|
|
|
from the `Environment`. You could shortcut `MyConfiguration` above by making sure
|
|
|
|
|
`FooProperties` is a already a bean:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@Component
|
|
|
|
|
@ConfigurationProperties(prefix="connection")
|
|
|
|
|
public class ConnectionProperties {
|
|
|
|
|
@ConfigurationProperties(prefix="foo")
|
|
|
|
|
public class FooProperties {
|
|
|
|
|
|
|
|
|
|
// ... getters and setters
|
|
|
|
|
// ... see above
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
@ -896,9 +956,13 @@ This style of configuration works particularly well with the
|
|
|
|
|
----
|
|
|
|
|
# application.yml
|
|
|
|
|
|
|
|
|
|
connection:
|
|
|
|
|
username: admin
|
|
|
|
|
remoteAddress: 192.168.1.1
|
|
|
|
|
foo:
|
|
|
|
|
remote-address: 192.168.1.1
|
|
|
|
|
security:
|
|
|
|
|
username: foo
|
|
|
|
|
roles:
|
|
|
|
|
- USER
|
|
|
|
|
- ADMIN
|
|
|
|
|
|
|
|
|
|
# additional configuration as required
|
|
|
|
|
----
|
|
|
|
@ -911,26 +975,27 @@ as any other bean.
|
|
|
|
|
@Service
|
|
|
|
|
public class MyService {
|
|
|
|
|
|
|
|
|
|
private final ConnectionProperties connection;
|
|
|
|
|
private final FooProperties properties;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
public MyService(ConnectionProperties connection) {
|
|
|
|
|
this.connection = connection;
|
|
|
|
|
public MyService(FooProperties properties) {
|
|
|
|
|
this.properties = properties;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//...
|
|
|
|
|
|
|
|
|
|
@PostConstruct
|
|
|
|
|
public void openConnection() {
|
|
|
|
|
Server server = new Server();
|
|
|
|
|
this.connection.configure(server);
|
|
|
|
|
Server server = new Server(this.properties.getRemoteAddress());
|
|
|
|
|
// ...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
TIP: Using `@ConfigurationProperties` also allows you to generate meta-data files that can
|
|
|
|
|
be used by IDEs. See the <<configuration-metadata>> appendix for details.
|
|
|
|
|
be used by IDEs to offer auto-completion for your own keys, see the
|
|
|
|
|
<<configuration-metadata>> appendix for details.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -945,15 +1010,15 @@ its bean registration:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@ConfigurationProperties(prefix = "foo")
|
|
|
|
|
@ConfigurationProperties(prefix = "bar")
|
|
|
|
|
@Bean
|
|
|
|
|
public FooComponent fooComponent() {
|
|
|
|
|
public BarComponent barComponent() {
|
|
|
|
|
...
|
|
|
|
|
}
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Any property defined with the `foo` prefix will be mapped onto that `FooComponent` bean
|
|
|
|
|
in a similar manner as the `ConnectionProperties` example above.
|
|
|
|
|
Any property defined with the `bar` prefix will be mapped onto that `BarComponent` bean
|
|
|
|
|
in a similar manner as the `FooProperties` example above.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1031,8 +1096,8 @@ annotations to your `@ConfigurationProperties` class:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@ConfigurationProperties(prefix="connection")
|
|
|
|
|
public class ConnectionProperties {
|
|
|
|
|
@ConfigurationProperties(prefix="foo")
|
|
|
|
|
public class FooProperties {
|
|
|
|
|
|
|
|
|
|
@NotNull
|
|
|
|
|
private InetAddress remoteAddress;
|
|
|
|
@ -1044,23 +1109,25 @@ annotations to your `@ConfigurationProperties` class:
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
`FooProperties` example:
|
|
|
|
|
|
|
|
|
|
[source,java,indent=0]
|
|
|
|
|
----
|
|
|
|
|
@ConfigurationProperties(prefix="connection")
|
|
|
|
|
public class ConnectionProperties {
|
|
|
|
|
public class FooProperties {
|
|
|
|
|
|
|
|
|
|
@NotNull
|
|
|
|
|
private InetAddress remoteAddress;
|
|
|
|
|
|
|
|
|
|
@Valid
|
|
|
|
|
private RemoteAddress remoteAddress;
|
|
|
|
|
private final Security security = new Security();
|
|
|
|
|
|
|
|
|
|
// ... getters and setters
|
|
|
|
|
|
|
|
|
|
public static class RemoteAddress {
|
|
|
|
|
public static class Security {
|
|
|
|
|
|
|
|
|
|
@NotEmpty
|
|
|
|
|
public String hostname;
|
|
|
|
|
public String username;
|
|
|
|
|
|
|
|
|
|
// ... getters and setters
|
|
|
|
|
|
|
|
|
|