Property Source

jim stafford

Introduction

Goals

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

Objectives

At the conclusion of this lecture and related exercises, the student will be able to:

  1. configure a Spring Boot application using a property file

  2. specify a property file for a basename

  3. specify a property file packaged within a JAR file

  4. specify a property file located on the file system

  5. specify a both properties and YAML property file sources

  6. specify multiple files to derive an injected property from

  7. specify properties based on an active profile

  8. specify properties based on placeholder values

  9. specify property overrides using different external source options

Property File Source(s)

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

spring.config.name

  • one or more base filenames separated by commas

  • default is application

  • suffixes searched for are .properties and .yml(or .yaml)

spring.profiles.active

  • 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)

spring.config.location

  • one or more directories/packages to search for configuration files or explicit references to specific files

  • default is:

    1. file:config/ - within a config directory in the current directory

    2. file:./ - within the current directory

    3. classpath:/config/ - within a config package in the classpath

    4. classpath:/ — within the root package of the classpath

Property File Source Example

First example

  • demonstrates spring.config.name and spring.config.location

  • uses a single value injection similar to previous examples

Value Injection Target
//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

Example Module Property Files

Source Tree
src
`-- main
    |-- java
    |   `-- ...
    `-- resources
        |-- alternate_source.properties
        |-- alternate_source.yml
        |-- application.properties
        `-- property_source.properties
JAR File
$ 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

Example Property File Contents

  • 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

Default Property Examples

$ 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

Non-existent Path

If you supply a non-existent path, Spring will report that as an error.

Location Directories Must Exist
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.

Making Location Directory Optional
java -jar target/appconfig-propertysource-example-*-SNAPSHOT-bootexec.jar \
  --spring.config.location="file:src/main/resources/,optional:file:src/main/resources/does_not_exit/"

Path not Ending with Slash ("/")

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

Alternate File Examples

#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

Series of files

#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

@PropertySource Annotation

  • Trimmed down example

Example Source Tree
|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- info
        |       `-- ejava
        |           `-- examples
        |               `-- app
        |                   `-- config
        |                       `-- propertysource
        |                           `-- annotation
        |                               |-- AppCommand.java
        |                               `-- PropertySourceApp.java
        `-- resources
            `-- property_source.properties

Annotation Reference

  • 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 {
...
1An 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

Factory-Default Property Source

  • @PropertySource references make for a convenient location for components to package factory-supplied, low-priority defaults that can be easily overridden

Profiles

  • 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.

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

Injected Component

  • 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.

Default Profile

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
1commonProperty was set to the value from default profile
2application.properties was loaded
3the default profile was loaded
4site1 and site2 profiles where not loaded

Specific Active Profile

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)
1commonProperty was set to the value from site1 profile
2application.properties was loaded
3default and site2 profiles were not loaded
4the site1 profile was loaded

Multiple Active Profiles

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)
1commonProperty was set to the value from last specified profile
2application.properties was loaded
3the default profile was not loaded
4site1 and site2 profiles were loaded

No Associated Profile

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
1No profiles where loaded for spring.config.name BOGUS

Property Placeholders

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

Placeholder Default Value

  • 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

Placeholder Demonstration

add three additional property files to the previous example

`-- src
    `-- main
        ...
        `-- resources
            |-- ...
            |-- myapp-site1.properties
            |-- myapp-site2.properties
            `-- myapp.properties

Placeholder Property Files

# myapp.properties
app.commonProperty=commonProperty from myapp.properties (2)
app.appProperty="${app.commonProperty}" used by myapp.property (1)
1defines a placeholder for another property
2defines 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
1defines a value for the placeholder
# myapp-site2.properties
app.commonProperty=commonProperty from myapp-site2.properties (1)
app.site2Property=site2Property from myapp-site2.properties
1defines a value for the placeholder

Placeholder Value Defined Internally

  • 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
1placeholder value coming from default value defined in same myapp.properties

Placeholder Value Defined in Profile

  • 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
1placeholder value coming from value defined in myapp-site1.properties

Multiple Active Profiles

  • 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
1placeholder value coming from value defined in last profile — myapp-site2.properties

Mixing Names, Profiles, and Location

$ 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

Other Common Property Sources

  • 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

    Component with app.audience @Value Injection
        @Value("${app.audience}")
        private String audience;

Property Source

  • @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 in the Scan Path References the Property Source
@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

Triggering Low-Priority Property Source

  • @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

application.properties

  • allow application to use "application" config name

  • application.properties file will take next precedence

application.properties with app.audience Property
src
`-- main
    |-- ...
    `-- resources
        |-- application.properties

#application.properties
app.audience=application.properties value


Property File Property Source
$ 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

Profiles

  • The next level of override is a profile

application-example.properties
#application-example.properties
app.audience=application-example.properties value
Profile Overrides
$ java -jar target/appconfig-propertysource-example-6.1.0-SNAPSHOT-bootexec.jar \
--spring.profiles.active=example

Application @Bean says Hey application-example.properties value

Environment Variables

  • 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"

Environment Variable Source Overrides Property File Source
$ (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
2environment variable overrides file source and example profile source

Express environment variable and command in subshell parens ('()') versus polluting current shell

(export APP_AUDIENCE=... && cmd)

Use unset to remove an environment variable from the current bash shell.

unset APP_AUDIENCE

Relaxed binding rules prevent environment variables from expressing case-sensitive values

logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG

Java System Properties

Java system property overriding the environment variable

Java System Property - Property Source
$ (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
2system property overrides environment variable and file source

spring.application.json

  • 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

JSON Expressed as Environment Variable

spring.application.json Expressed as Environment Variable
$ (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
2spring.application.json overrides system property, environment variable and file

JSON Expressed as System Property

spring.application.json Expressed as System Property
(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
2system property expression overrides environment variable expression

Command Line Arguments

command line argument overriding everything we have shown defined to date

Command Line Argument Property Source
$ (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
2command line argument overrides spring.application.json, system property, environment variable and file

@SpringBootTest.properties

  • future testing topic

  • @SpringBootTest.properties declaration overrides all other property sources

SpringBootTest Property Source
@SpringBootTest(
        properties={"app.audience=test"}
public class SampleNTest {

Summary

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.