user1726919
user1726919

Reputation: 83

Spring spring.profiles.include: doesn't read profile-related properties

There are several ways present to define "active profiles" for a Spring Boot application. The default one is to pass it through a command line, like this:

java -Dspring.profiles.active=dev,local -jar myapp.jar

it works just fine (as expected): All three sets of profile-related properties will be loaded in proper order:

  1. application.yaml
  2. application-dev.yaml will override the previous one
  3. application-local.yaml will override the previous one as well (these properties will have the most priority)

Based on the idea, that my "local" profile should always "use and overrides" properties from the "dev", let's "hardcode" such behavior.

Let's use the 'spring.profiles.include' feature for this. So, the following lines are added to the 'application-local.yaml':

spring.profiles:
    include:
        - dev

I expect, now I can pass the "local" profile only in the command line, and the "dev" profile will be applied automatically (with his properties, of course):

java -Dspring.profiles.active=local -jar myapp.jar

But ooop!*: properties from the 'application-dev.yaml' are ignored.

Why? Is it a bug? Is it a feature that forces me to list all profiles in a command line directly?

I'm sure that the behavior around profiles activation should be the same without any difference in how the active-profiles list was passed to Spring Boot framework.

The application:

@SpringBootApplication @EnableConfigurationProperties( MyProps::class )
class SpringApp4

@ConfigurationProperties("my.db") @ConstructorBinding
data class MyProps(val name: String, val url:  String, val user: String)

@Component
class MyRunner(val myProps: MyProps, val env: Environment) : CommandLineRunner {
    override fun run(vararg args: String) {
        println("myProps         = $myProps")
        println("activeProfiles  = ${env.activeProfiles.joinToString()}")
        exitProcess(0)
    }
}

fun main() { runApplication<SpringApp4>() }

application.yaml:

my.db:
    name: "default-name"
    url:  "default-url"
    user: "default-user"

application-dev.yaml:

my.db:
    url:  "dev-url"
    user: "dev-user"

application-local.yaml:

spring.profiles.include:
    - dev
my.db:
    user: "local-user"

Run1: java -Dspring.profiles.active=dev,local -jar myapp.jar Correct output:

myProps         = MyProps(name=default-name, url=dev-url, user=local-user)
activeProfiles  = dev, local

it's correct because the url=dev-url

Run2: java -Dspring.profiles.active=local -jar myapp.jar Incorrect output:

myProps         = MyProps(name=default-name, url=default-url, user=local-user)
activeProfiles  = local

It's not correct because the url=default-url and the activeProfiles doesn't contain the "dev" at all.

Help me please to figure out how to use the spring.profiles.include feature in yaml to build a kind of top level profiles that will activate other automatically.

Upvotes: 1

Views: 2245

Answers (2)

gavenkoa
gavenkoa

Reputation: 48753

spring.profiles.include deprecated in Spring Boot 2.4 and no longer works: https://spring.io/blog/2020/08/14/config-file-processing-in-spring-boot-2-4

It caused recursive resource loading; that broke Kubernates ConfigMap so they removed recursion.

Use spring.profiles.active or spring.profiles.group.

Upvotes: 0

Nakul Goyal
Nakul Goyal

Reputation: 659

In Run2 You are giving profile as local i.e

-Dspring.profiles.active=local

So spring will first load application.yml and then application-local.yml

I can see the output is expected.

Since some properties like name and url are not present in application-local.yml, so the values of these fields will be same as present in application.yml

FYI : application.yml is always called irrespective of profile, and then it gets overridden by the profile mentioned in -Dspring.profiles.active property

Upvotes: 0

Related Questions