jim stafford
The student will learn:
to supply groups of properties using files
to configure a Spring Boot application using property files
to flexibly configure and control configurations applied
At the conclusion of this lecture and related exercises, the student will be able to:
configure a Spring Boot application using a property file
specify a property file for a basename
specify a property file packaged within a JAR file
specify a property file located on the file system
specify a both properties
and YAML
property file sources
specify multiple files to derive an injected property from
specify properties based on an active profile
specify properties based on placeholder values
specify property overrides using different external source options
Spring Boot uses three key properties for configuration files (Ref: docs.spring.io):
spring.config.name
primarily used to identify the base name of the application (e.g., application
or myapp
) or
of distinct areas (e.g., database
, security
)
spring.profiles.active
primarily used to supply variants of property values
spring.config.location
primarily used to identify the search paths to look for configuration files but can be used to override names and profiles when a complete file path is supplied
one or more base filenames separated by commas
default is application
suffixes searched for are .properties
and .yml
(or .yaml
)
one or more profile names separated by commas
default is default
located at the end of the base filename separated by a dash (-
; e.g., application-default
)
one or more directories/packages to search for configuration files or explicit references to specific files
default is:
file:config/
- within a config
directory in the current directory
file:./
- within the current directory
classpath:/config/
- within a config
package in the classpath
classpath:/
— within the root package of the classpath
First example
demonstrates spring.config.name
and spring.config.location
uses a single value injection similar to previous examples
//AppCommand.java
...
@Value("${app.audience}")
private String audience;
...
However, the source of the property value
will not come from the command line
will come from one of the following property and/or YAML files in our module
src
`-- main
|-- java
| `-- ...
`-- resources
|-- alternate_source.properties
|-- alternate_source.yml
|-- application.properties
`-- property_source.properties
$ jar tf target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar | \
egrep 'classes.*(properties|yml)'
BOOT-INF/classes/alternate_source.properties
BOOT-INF/classes/alternate_source.yml
BOOT-INF/classes/property_source.properties
BOOT-INF/classes/application.properties
Each declare the same property app.audience
with a different value
Spring Boot primarily supports the two file types shown
(properties
and
YAML
)
There is
some support for JSON
XML
is primarily used to define configurations
#property_source.properties
app.audience=Property Source value
#alternate_source.properties
app.audience=alternate source property file
#application.properties
app.audience=application.properties value
#alternate_source.yml
app:
audience: alternate source YAML file
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar
...
Application @Bean says Hey application.properties value
can also be completed with
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="classpath:/"
...
Application @Bean says Hey application.properties value
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="file:src/main/resources/"
...
Application @Bean says Hey application.properties value
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="file:src/main/resources/application.properties"
...
Application @Bean says Hey application.properties value
$ cp src/main/resources/application.properties /tmp/xyz.properties
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=xyz --spring.config.location="file:/tmp/"
...
Application @Bean says Hey application.properties value
If you supply a non-existent path, Spring will report that as an error.
java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="file:src/main/resources/,file:src/main/resources/does_not_exit/"
[main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter --
***************************
APPLICATION FAILED TO START
***************************
Description:
Config data location 'file:src/main/resources/does_not_exit/' does not exist
Action:
Check that the value 'file:src/main/resources/does_not_exit/' is correct, or prefix it with 'optional:'
You can mark the location with optional:
for cases where it is legitimate for the location not to exist.
java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="file:src/main/resources/,optional:file:src/main/resources/does_not_exit/"
If you supply a path not ending with a slash ("/"), Spring will also report an error.
java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="file:src/main/resources"
...
14:28:23.544 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Unable to load config data from 'file:src/main/resources'
...
Caused by: java.lang.IllegalStateException: File extension is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/' or File.separator
#property_source.properties
app.audience=Property Source value
#alternate_source.properties
app.audience=alternate source property file
#alternate_source.yml
app:
audience: alternate source YAML file
can be used to produce
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=property_source
...
Application @Bean says Hey Property Source value
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=alternate_source
...
Application @Bean says Hey alternate source property file
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.location="classpath:alternate_source.properties,classpath:alternate_source.yml"
...
Application @Bean says Hey alternate source YAML file
#property_source.properties
app.audience=Property Source value
#alternate_source.properties
app.audience=alternate source property file
The default priority is last specified.
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name="property_source,alternate_source"
...
Application @Bean says Hey alternate source property file
$ java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name="alternate_source,property_source"
...
Application @Bean says Hey Property Source value
Trimmed down example
|-- pom.xml
`-- src
`-- main
|-- java
| `-- info
| `-- ejava
| `-- examples
| `-- app
| `-- config
| `-- propertysource
| `-- annotation
| |-- AppCommand.java
| `-- PropertySourceApp.java
`-- resources
`-- property_source.properties
Java annotation will express a non-default property file
#property_source.properties
app.audience=Property Source value
...
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@PropertySource("classpath:property_source.properties") (1)
public class PropertySourceApp {
...
1 | An explicit reference to the properties file is placed within the
annotation on the @Configuration class |
Executing our application results in custom property file used
java -jar target/appconfig-propertysource-annotation-example-*-SNAPSHOT-bootexec.jar
...
Application @Bean says Hey Property Source value
@PropertySource
references make for a convenient location for components to package factory-supplied, low-priority defaults that can be easily overridden
Spring also leverages profiles within configurations
identified by -(profileName)
at the end of the base filename
|-- pom.xml
`-- src
`-- main
|-- java
| `-- info
| `-- ejava
| `-- examples
| `-- app
| `-- config
| `-- propertysource
| `-- profiles
| |-- AppCommand.java
| `-- PropertySourceApp.java
`-- resources
|-- application-default.properties
|-- application-site1.properties
|-- application-site2.properties
`-- application.properties
The example uses the default spring.config.name
of application
and supplies four
property files.
each of the property files supplies a common property of app.commonProperty
to
help demonstrate priority
each of the property files supplies a unique property to help identify whether the file was used
#application.properties
app.commonProperty=commonProperty from application.properties
app.appProperty=appProperty from application.properties
#application-default.properties
app.commonProperty=commonProperty from application-default.properties
app.defaultProperty=defaultProperty from application-default.properties
#application-site1.properties
app.commonProperty=commonProperty from application-site1.properties
app.site1Property=site1Property from application-site1.properties
#application-site2.properties
app.commonProperty=commonProperty from application-site2.properties
app.site2Property=site2Property from application-site2.properties
component class
defines an attribute for each of the available properties
defines a default value to identify when they have not been supplied
@Component
public class AppCommand implements CommandLineRunner {
@Value("${app.commonProperty:not supplied}")
private String commonProperty;
@Value("${app.appProperty:not supplied}")
private String appProperty;
@Value("${app.defaultProperty:not supplied}")
private String defaultProperty;
@Value("${app.site1Property:not supplied}")
private String site1Property;
@Value("${app.site2Property:not supplied}")
private String site2Property;
In all cases (except when using an alternate spring.config.name ), we will get
the application.properties loaded. However, it is used at a lower priority
than all other sources. |
If we run the program with no profiles active, we enact the default
profile.
site1
and site2
profiles are not loaded.
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar
...
commonProperty=commonProperty from application-default.properties (1)
appProperty=appProperty from application.properties (2)
defaultProperty=defaultProperty from application-default.properties (3)
site1Property=not supplied (4)
site2Property=not supplied
1 | commonProperty was set to the value from default profile |
2 | application.properties was loaded |
3 | the default profile was loaded |
4 | site1 and site2 profiles where not loaded |
If we activate a specific profile (site1
) the associated file is loaded
and the alternate profiles — including default
— are not loaded.
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.profiles.active=site1
...
commonProperty=commonProperty from application-site1.properties (1)
appProperty=appProperty from application.properties (2)
defaultProperty=not supplied (3)
site1Property=site1Property from application-site1.properties (4)
site2Property=not supplied (3)
1 | commonProperty was set to the value from site1 profile |
2 | application.properties was loaded |
3 | default and site2 profiles were not loaded |
4 | the site1 profile was loaded |
We can activate multiple profiles at the same time
later one specified takes priority
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.profiles.active=site1,site2 (1)
...
commonProperty=commonProperty from application-site2.properties (1)
appProperty=appProperty from application.properties (2)
defaultProperty=not supplied (3)
site1Property=site1Property from application-site1.properties (4)
site2Property=site2Property from application-site2.properties (4)
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.profiles.active=site2,site1 (1)
...
commonProperty=commonProperty from application-site1.properties (1)
appProperty=appProperty from application.properties (2)
defaultProperty=not supplied (3)
site1Property=site1Property from application-site1.properties (4)
site2Property=site2Property from application-site2.properties (4)
1 | commonProperty was set to the value from last specified profile |
2 | application.properties was loaded |
3 | the default profile was not loaded |
4 | site1 and site2 profiles were loaded |
If there are no associated profiles with a given spring.config.name
, then
none will be loaded.
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=BOGUS --spring.profiles.active=site1 (1)
...
commonProperty=not supplied (1)
appProperty=not supplied
defaultProperty=not supplied
site1Property=not supplied
site2Property=not supplied
1 | No profiles where loaded for spring.config.name BOGUS |
Build property values using a placeholder that will come from elsewhere
Example — set of full URLs that change based on a single base URL value
(config_name).properties
would be the candidate to host the following definition
security.authn=${security.service.url}/authentications?user=:user
security.authz=${security.service.url}/authorizations/roles?user=:user
profiles would host the specific value for the placeholder
(config_name)-(profileA).properties
security.service.url=http://localhost:8080
(config_name)-(profileB).properties
security.service.url=https://acme.com
the default value for the placeholder can be declared in the same property file that uses it
security.service.url=https://acme.com
security.authn=${security.service.url}/authentications?user=:user
security.authz=${security.service.url}/authorizations/roles?user=:user
add three additional property files to the previous example
`-- src
`-- main
...
`-- resources
|-- ...
|-- myapp-site1.properties
|-- myapp-site2.properties
`-- myapp.properties
# myapp.properties
app.commonProperty=commonProperty from myapp.properties (2)
app.appProperty="${app.commonProperty}" used by myapp.property (1)
1 | defines a placeholder for another property |
2 | defines a default value for the placeholder within this file |
Only the ${} characters and property name are specific to property placeholders. Quotes ("" ) within this property value are part of this example and not anything specific to property placeholders in general. |
# myapp-site1.properties
app.commonProperty=commonProperty from myapp-site1.properties (1)
app.site1Property=site1Property from myapp-site1.properties
1 | defines a value for the placeholder |
# myapp-site2.properties
app.commonProperty=commonProperty from myapp-site2.properties (1)
app.site2Property=site2Property from myapp-site2.properties
1 | defines a value for the placeholder |
no profile defined
# myapp.properties
app.commonProperty=commonProperty from myapp.properties
app.appProperty="${app.commonProperty}" used by myapp.property
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=myapp
...
commonProperty=commonProperty from myapp.properties
appProperty="commonProperty from myapp.properties" used by myapp.property (1)
defaultProperty=not supplied
site1Property=not supplied
site2Property=not supplied
1 | placeholder value coming from default value defined in same myapp.properties |
site1
profile active
# myapp-site1.properties
app.commonProperty=commonProperty from myapp-site1.properties
app.site1Property=site1Property from myapp-site1.properties
# myapp.properties
app.commonProperty=commonProperty from myapp.properties
app.appProperty="${app.commonProperty}" used by myapp.property
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=myapp --spring.profiles.active=site1
...
commonProperty=commonProperty from myapp-site1.properties
appProperty="commonProperty from myapp-site1.properties" used by myapp.property (1)
defaultProperty=not supplied
site1Property=site1Property from myapp-site1.properties
site2Property=not supplied
1 | placeholder value coming from value defined in myapp-site1.properties |
multiple profiles activate
# myapp-site1.properties
app.commonProperty=commonProperty from myapp-site1.properties
app.site1Property=site1Property from myapp-site1.properties
# myapp-site2.properties
app.commonProperty=commonProperty from myapp-site2.properties
app.site2Property=site2Property from myapp-site2.properties
# myapp.properties
app.commonProperty=commonProperty from myapp.properties
app.appProperty="${app.commonProperty}" used by myapp.property
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=myapp --spring.profiles.active=site1,site2
...
commonProperty=commonProperty from myapp-site2.properties
appProperty="commonProperty from myapp-site2.properties" used by myapp.property (1)
defaultProperty=not supplied
site1Property=site1Property from myapp-site1.properties
site2Property=site2Property from myapp-site2.properties
1 | placeholder value coming from value defined in last profile — myapp-site2.properties |
$ java -jar target/appconfig-propertysource-profile-example-*-SNAPSHOT-bootexec.jar \
--spring.config.name=myapp \
--spring.profiles.active=site1 \
--spring.config.location="file:src/main/resources/"
...
commonProperty=commonProperty from myapp-site1.properties
appProperty="commonProperty from myapp-site1.properties" used by myapp.property
defaultProperty=not supplied
site1Property=site1Property from myapp-site1.properties
site2Property=not supplied
locates the following property files in the filesystem (not classpath)
src/main/resources/myapp.properties
src/main/resources/myapp-site1.properties
Property files and profiles are a primary way to configure applications in bulk
Helpful to know other ways to supply or override properties externally
Example: deployment platforms where you do not control the command line
Spring.io lists about a dozen sources of other property sources in priority order
I will cover ones that have been the most common and helpful for me in low-to-high Spring priority order
Each example will inject value into a printed component property
@Value("${app.audience}")
private String audience;
@PropertySource
is one of the lowest priority sources
supplying a custom property file
referencing it from a @Configuration
using classpath:
reference to file from module JAR
@Configuration
@PropertySource(name="propertySource",
value = "classpath:info/ejava/examples/app/config/propertysource/packaged_propertySource.properties")
public class PropertySourceConfiguration { }
#packaged_propertySource.properties
app.audience=packaged_propertySource.properties value
@PropertySource
is the lowest priority source of these examples
supplying fictitious spring.config.name
so no default profile override it
$ java -jar target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar \
--spring.config.name=none
Application @Bean says Hey packaged_propertySource.properties value
allow application to use "application" config name
application.properties
file will take next precedence
src
`-- main
|-- ...
`-- resources
|-- application.properties
#application.properties
app.audience=application.properties value
$ java -jar target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar
Application @Bean says Hey application.properties value (1)
1 | "application.properties value" comes from a property file |
The next level of override is a profile
#application-example.properties
app.audience=application-example.properties value
$ java -jar target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar \
--spring.profiles.active=example
Application @Bean says Hey application-example.properties value
override the property file spec using an environment variable
expressed in ALL_CAPS with an underscore (_
) replacing all dots (.
)
bash expression is export APP_AUDIENCE="some value"
$ (export APP_AUDIENCE=env && \(1)
java -jar target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar \
--spring.profiles.active=example)
Application @Bean says Hey env (2)
1 | "env" comes from an environment variable |
2 | environment variable overrides file source and example profile source |
Express environment variable and command in subshell parens ('()') versus polluting current shell
|
Use
|
Relaxed binding rules prevent environment variables from expressing case-sensitive values
|
Java system property overriding the environment variable
$ (export APP_AUDIENCE=env &&
java -jar \
-Dapp.audience=sys \(1)
target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar)
Application @Bean says Hey sys (2)
1 | "sys" comes from system property |
2 | system property overrides environment variable and file source |
properties expressed within a JSON document supplied by the spring.application.json
property
can be expressed as an environment variable, Java system property, or command line
JSON will be used based on the priority of the source
properties within the JSON will override what we have demonstrated so far
$ (export APP_AUDIENCE=env && \
SPRING_APPLICATION_JSON='{"app.audience":"envjson"}' && \(1)
java -jar -Dapp.audience=sys \
target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar)
Application @Bean says Hey envjson (2)
1 | "envjson" comes from spring.application.json property expressed using environment variable |
2 | spring.application.json overrides system property, environment variable and file |
(export APP_AUDIENCE=env && \
SPRING_APPLICATION_JSON='{"app.audience":"envjson"}' && \
java -jar \
-Dapp.audience=sys \
-Dspring.application.json='{"app.audience":"sysjson"}' \(1)
target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar)
Application @Bean says Hey sysjson (2)
1 | "sysjson" comes from spring.application.json property expressed using system property |
2 | system property expression overrides environment variable expression |
command line argument overriding everything we have shown defined to date
$ (export APP_AUDIENCE=env && \
SPRING_APPLICATION_JSON='{"app.audience":"envjson"}' && \
java -jar \
-Dapp.audience=sys \
-Dspring.application.json='{"app.audience":"sysjson"}' \
target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar \
--app.audience=cmdarg) (1)
Application @Bean says Hey cmdarg (2)
1 | "cmdarg" comes from command line argument |
2 | command line argument overrides spring.application.json , system property, environment variable and file |
future testing topic
@SpringBootTest.properties
declaration overrides all other property sources
@SpringBootTest(
properties={"app.audience=test"}
public class SampleNTest {
In this module we
supplied property value(s) through a set of property files
used both properties
and YAML
formatted files to express property values
specified base filename(s) to use using the --spring.config.name
property
specified profile(s) to use using the --spring.profiles.active
property
specified paths(s) to search using the --spring.config.location
property
specified a custom file to load using the @PropertySource
annotation
specified multiple names, profiles, and locations
specified property overrides through multiple types of external sources
In future modules we will show how to leverage these property sources in a way that can make configuring the Java code easier.