Spring Boot lets you externalize your configuration so that you can work with the same
application code in different environments. You can use properties files, YAML files,
environment variables, and command-line arguments to externalize configuration. Property
values can be injected directly into your beans by using the @Value
annotation,
accessed through Spring’s Environment
abstraction, or be
bound to structured
objects through @ConfigurationProperties
.
Spring Boot uses a very particular PropertySource
order that is designed to allow
sensible overriding of values. Properties are considered in the following order:
~/.spring-boot-devtools.properties
when devtools is active).@TestPropertySource
annotations on your tests.@SpringBootTest#properties
annotation attribute on your tests.SPRING_APPLICATION_JSON
(inline JSON embedded in an environment
variable or system property).ServletConfig
init parameters.ServletContext
init parameters.java:comp/env
.System.getProperties()
).RandomValuePropertySource
that has properties only in random.*
.application-{profile}.properties
and YAML variants).application-{profile}.properties
and YAML variants).application.properties
and YAML
variants).application.properties
and YAML
variants).@PropertySource
annotations on your @Configuration
classes.SpringApplication.setDefaultProperties
).To provide a concrete example, suppose you develop a @Component
that uses a name
property, as shown in the following example:
import org.springframework.stereotype.* import org.springframework.beans.factory.annotation.* @Component public class MyBean { @Value("${name}") private String name; // ... }
On your application classpath (for example, inside your jar) you can have an
application.properties
file that provides a sensible default property value for name
.
When running in a new environment, an application.properties
file can be provided
outside of your jar that overrides the name
. For one-off testing, you can launch with a
specific command line switch (for example, java -jar app.jar --name="Spring"
).
Tip | |
---|---|
The $ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar In the preceding example, you end up with $ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar You can also supply the JSON by using a command line argument, as shown in the following example: $ java -jar myapp.jar --spring.application.json='{"name":"test"}' You can also supply the JSON as a JNDI variable, as follows:
|
The RandomValuePropertySource
is useful for injecting random values (for example, into
secrets or test cases). It can produce integers, longs, uuids, or strings, as shown in the
following example:
my.secret=${random.value} my.number=${random.int} my.bignumber=${random.long} my.uuid=${random.uuid} my.number.less.than.ten=${random.int(10)} my.number.in.range=${random.int[1024,65536]}
The random.int*
syntax is OPEN value (,max) CLOSE
where the OPEN,CLOSE
are any
character and value,max
are integers. If max
is provided, then value
is the minimum
value and max
is the maximum value (exclusive).
By default, SpringApplication
converts any command line option arguments (that is,
arguments starting with --
, such as --server.port=9000
) to a property
and adds
them to the Spring Environment
. As mentioned previously, command line properties always
take precedence over other property sources.
If you do not want command line properties to be added to the Environment
, you can
disable them by using SpringApplication.setAddCommandLineProperties(false)
.
SpringApplication
loads properties from application.properties
files in the following
locations and adds them to the Spring Environment
:
/config
subdirectory of the current directory/config
packageThe list is ordered by precedence (properties defined in locations higher in the list override those defined in lower locations).
Note | |
---|---|
You can also use YAML ('.yml') files as an alternative to '.properties'. |
If you do not like application.properties
as the configuration file name, you can
switch to another file name by specifying a spring.config.name
environment property.
You can also refer to an explicit location by using the spring.config.location
environment property (which is a comma-separated list of directory locations or file
paths). The following example shows how to specify a different file name:
$ java -jar myproject.jar --spring.config.name=myproject
The following example shows how to specify two locations:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
Warning | |
---|---|
|
If spring.config.location
contains directories (as opposed to files), they should end
in /
(and, at runtime, be appended with the names generated from spring.config.name
before being loaded, including profile-specific file names). Files specified in
spring.config.location
are used as-is, with no support for profile-specific variants,
and are overridden by any profile-specific properties.
Config locations are searched in reverse order. By default, the configured locations are
classpath:/,classpath:/config/,file:./,file:./config/
. The resulting search order is
the following:
file:./config/
file:./
classpath:/config/
classpath:/
When custom config locations are configured by using spring.config.location
, they
replace the default locations. For example, if spring.config.location
is configured with
the value classpath:/custom-config/,file:./custom-config/
, the search order becomes the
following:
file:./custom-config/
classpath:custom-config/
Alternatively, when custom config locations are configured by using
spring.config.additional-location
, they are used in addition to the default locations.
Additional locations are searched before the default locations. For example, if
additional locations of classpath:/custom-config/,file:./custom-config/
are configured,
the search order becomes the following:
file:./custom-config/
classpath:custom-config/
file:./config/
file:./
classpath:/config/
classpath:/
This search ordering lets you specify default values in one configuration file and then
selectively override those values in another. You can provide default values for your
application in application.properties
(or whatever other basename you choose with
spring.config.name
) in one of the default locations. These default values can then be
overridden at runtime with a different file located in one of the custom locations.
Note | |
---|---|
If you use environment variables rather than system properties, most operating
systems disallow period-separated key names, but you can use underscores instead (for
example, |
Note | |
---|---|
If your application runs in a container, then JNDI properties (in |
In addition to application.properties
files, profile-specific properties can also be
defined by using the following naming convention: application-{profile}.properties
. The
Environment
has a set of default profiles (by default, [default]
) that are used if no
active profiles are set. In other words, if no profiles are explicitly activated, then
properties from application-default.properties
are loaded.
Profile-specific properties are loaded from the same locations as standard
application.properties
, with profile-specific files always overriding the non-specific
ones, whether or not the profile-specific files are inside or outside your
packaged jar.
If several profiles are specified, a last-wins strategy applies. For example, profiles
specified by the spring.profiles.active
property are added after those configured
through the SpringApplication
API and therefore take precedence.
Note | |
---|---|
If you have specified any files in |
The values in application.properties
are filtered through the existing Environment
when they are used, so you can refer back to previously defined values (for example, from
System properties).
app.name=MyApp app.description=${app.name} is a Spring Boot application
Tip | |
---|---|
You can also use this technique to create “short” variants of existing Spring Boot properties. See the Section 73.4, “Use ‘Short’ Command Line Arguments” how-to for details. |
YAML is a superset of JSON and, as such, is a convenient format for
specifying hierarchical configuration data. The SpringApplication
class automatically
supports YAML as an alternative to properties whenever you have the
SnakeYAML library on your classpath.
Note | |
---|---|
If you use “Starters”, SnakeYAML is automatically provided by
|
Spring Framework provides two convenient classes that can be used to load YAML documents.
The YamlPropertiesFactoryBean
loads YAML as Properties
and the YamlMapFactoryBean
loads YAML as a Map
.
For example, consider the following YAML document:
environments: dev: url: http://dev.example.com name: Developer Setup prod: url: http://another.example.com name: My Cool App
The preceding example would be transformed into the following properties:
environments.dev.url=http://dev.example.com environments.dev.name=Developer Setup environments.prod.url=http://another.example.com environments.prod.name=My Cool App
YAML lists are represented as property keys with [index]
dereferencers. For example,
consider the following YAML:
my: servers: - dev.example.com - another.example.com
The preceding example would be transformed into these properties:
my.servers[0]=dev.example.com my.servers[1]=another.example.com
To bind to properties like that by using the Spring DataBinder
utilities (which is what
@ConfigurationProperties
does), you need to have a property in the target bean of type
java.util.List
(or Set
) and you either need to provide a setter or initialize it with
a mutable value. For example, the following example binds to the properties shown
previously:
@ConfigurationProperties(prefix="my") public class Config { private List<String> servers = new ArrayList<String>(); public List<String> getServers() { return this.servers; } }
Note | |
---|---|
When lists are configured in more than one place, overriding works by replacing the entire
list. In the preceding example, when |
The YamlPropertySourceLoader
class can be used to expose YAML as a PropertySource
in
the Spring Environment
. Doing so lets you use the @Value
annotation with placeholders
syntax to access YAML properties.
You can specify multiple profile-specific YAML documents in a single file by using a
spring.profiles
key to indicate when the document applies, as shown in the following
example:
server: address: 192.168.1.100 --- spring: profiles: development server: address: 127.0.0.1 --- spring: profiles: production server: address: 192.168.1.120
In the preceding example, if the development
profile is active, the server.address
property is 127.0.0.1
. Similarly, if the production
profile is active, the
server.address
property is 192.168.1.120
. If the development
and production
profiles are not enabled, then the value for the property is 192.168.1.100
.
If none are explicitly active when the application context starts, the default profiles
are activated. So, in the following YAML, we set a value for spring.security.user.password
that is available only in the "default" profile:
server: port: 8000 --- spring: profiles: default security: user: password: weak
Whereas, in the following example, the password is always set because it is not attached to any profile, and it would have to be explicitly reset in all other profiles as necessary:
server: port: 8000 spring: security: user: password: weak
Spring profiles designated by using the spring.profiles
element may optionally be
negated by using the !
character. If both negated and non-negated profiles are
specified for a single document, at least one non-negated profile must match, and no
negated profiles may match.
YAML files cannot be loaded by using the @PropertySource
annotation. So, in the case
that you need to load values that way, you need to use a properties file.
As we showed earlier, any YAML content is ultimately transformed to properties. That process may be counter-intuitive when overriding “list” properties through a profile.
For example, assume a MyPojo
object with name
and description
attributes that are
null
by default. The following example exposes a list of MyPojo
objects from
AcmeProperties
:
@ConfigurationProperties("acme") public class AcmeProperties { private final List<MyPojo> list = new ArrayList<>(); public List<MyPojo> getList() { return this.list; } }
Consider the following configuration:
acme: list: - name: my name description: my description --- spring: profiles: dev acme: list: - name: my another name
If the dev
profile is not active, AcmeProperties.list
contains one MyPojo
entry,
as previously defined. If the dev
profile is enabled, however, the list
still
contains only one entry (with a name of my another name
and a description of null
).
This configuration does not add a second MyPojo
instance to the list, and it does not
merge the items.
When a collection is specified in multiple profiles, the one with the highest priority (and only that one) is used. Consider the following example:
acme: list: - name: my name description: my description - name: another name description: another description --- spring: profiles: dev acme: list: - name: my another name
In the preceding example, if the dev
profile is active, AcmeProperties.list
contains
one MyPojo
entry (with a name of my another name
and a description of null
).
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 lets strongly typed beans govern and validate the configuration of
your application, as shown in the following example:
package com.example; import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties("acme") public class AcmeProperties { private boolean enabled; private InetAddress remoteAddress; 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) { ... } } }
The preceding POJO defines the following properties:
acme.enabled
, with a value of false
by default.acme.remote-address
, with a type that can be coerced from String
.acme.security.username
, with a nested "security" object 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
.acme.security.password
.acme.security.roles
, with a collection of String
.Note | |
---|---|
Getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC. A setter may be omitted in the following cases:
Some people use Project Lombok to add getters and setters automatically. Make sure that Lombok does not generate any particular constructor for such a type, as it is used automatically by the container to instantiate the object. |
Tip | |
---|---|
See also the differences between |
You also need to list the properties classes to register in the
@EnableConfigurationProperties
annotation, as shown in the following example:
@Configuration @EnableConfigurationProperties(AcmeProperties.class) public class MyConfiguration { }
Note | |
---|---|
When the The bean name in the example above is |
Even if the preceding configuration creates a regular bean for AcmeProperties
, 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
is
configured from the Environment
. You could shortcut MyConfiguration
by making sure
AcmeProperties
is already a bean, as shown in the following example:
@Component @ConfigurationProperties(prefix="acme") public class AcmeProperties { // ... see the preceding example }
This style of configuration works particularly well with the SpringApplication
external
YAML configuration, as shown in the following example:
# application.yml acme: remote-address: 192.168.1.1 security: username: admin roles: - USER - ADMIN # additional configuration as required
To work with @ConfigurationProperties
beans, you can inject them in the same way
as any other bean, as shown in the following example:
@Service public class MyService { private final AcmeProperties properties; @Autowired public MyService(AcmeProperties properties) { this.properties = properties; } //... @PostConstruct public void openConnection() { Server server = new Server(this.properties.getRemoteAddress()); // ... } }
Tip | |
---|---|
Using |
As well as using @ConfigurationProperties
to annotate a class, you can also use it on
public @Bean
methods. Doing so 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, as shown in the following example:
@ConfigurationProperties(prefix = "another") @Bean public AnotherComponent anotherComponent() { ... }
Any property defined with the another
prefix is mapped onto that AnotherComponent
bean
in manner similar to the preceding AcmeProperties
example.
Spring Boot uses some relaxed rules for binding Environment
properties to
@ConfigurationProperties
beans, so there does not need to be an exact match between the
Environment
property name and the bean property name. Common examples where this is
useful include dash-separated environment properties (for example, context-path
binds
to contextPath
), and capitalized environment properties (for example, PORT
binds to
port
).
For example, consider the following @ConfigurationProperties
class:
@ConfigurationProperties(prefix="acme.my-project.person") public class OwnerProperties { private String firstName; public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } }
In the preceding example, the following properties names can all be used:
Table 24.1. relaxed binding
Property | Note |
---|---|
| Standard camel case syntax. |
| Kebab case, which is recommended for use in |
| Underscore notation, which is an alternative format for use in |
| Upper case format, which is recommended when using system environment variables. |
Note | |
---|---|
The |
Table 24.2. relaxed binding rules per property source
Property Source | Simple | List |
---|---|---|
Properties Files | Camel case, kebab case, or underscore notation | Standard list syntax using |
YAML Files | Camel case, kebab case, or underscore notation | Standard YAML list syntax or comma-separated values |
Environment Variables | Upper case format with underscore as the delimiter. | Numeric values surrounded by underscores, such as |
System properties | Camel case, kebab case, or underscore notation | Standard list syntax using |
Tip | |
---|---|
We recommend that, when possible, properties are stored in lower-case kebab format,
such as |
Spring attempts 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 a bean named conversionService
) or custom
property editors (through 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 |
Spring Boot attempts to validate @ConfigurationProperties
classes whenever they are
annotated with Spring’s @Validated
annotation. You can use JSR-303 javax.validation
constraint annotations directly on your configuration class. To do so, ensure that a
compliant JSR-303 implementation is on your classpath and then add constraint annotations
to your fields, as shown in the following example:
@ConfigurationProperties(prefix="acme") @Validated public class AcmeProperties { @NotNull private InetAddress remoteAddress; // ... getters and setters }
In order to validate the values of nested properties, you must annotate the associated
field as @Valid
to trigger its validation. The following example builds on the
preceding AcmeProperties
example:
@ConfigurationProperties(prefix="acme") @Validated public class AcmeProperties { @NotNull private InetAddress remoteAddress; @Valid private final Security security = new Security(); // ... getters and setters public static class Security { @NotEmpty public String username; // ... 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 lets the bean be created without having to
instantiate the @Configuration
class. Doing so avoids any problems that may be caused
by early instantiation. There is a
property
validation sample that shows how to set things up.
Tip | |
---|---|
The |
The @Value
annotation is a core container feature, and it does not provide the same
features as type-safe configuration properties. The following table summarizes the
features that are supported by @ConfigurationProperties
and @Value
:
Feature | @ConfigurationProperties | @Value |
---|---|---|
Yes | No | |
Yes | No | |
| No | Yes |
If you define a set of configuration keys for your own components, we recommend you
group them in a POJO annotated with @ConfigurationProperties
. You should also be aware
that, since @Value
does not support relaxed binding, it is not a good candidate if you
need to provide the value by using environment variables.
Finally, while you can write a SpEL
expression in @Value
, such expressions are not
processed from application
property files.