21

I'm trying to partition configuration properties for several Spring Boot applications. I'm using Spring Boot 1.1.6, and our configuration properties are expressed in YAML in the usual application.yml style. I've created various profiles for common base parameters, common DB parameters, etc. I was trying to use the include feature mentioned in the Spring Boot reference docs, but it seems to work as an override and not an include. I.e. exactly the opposite of what I want. Given the following content in application.yml, I would have expected the property name to have the value bar when the bar profile is active, but instead it gets set to foo (from the included profile). I thought the notion of including meant that it was loaded first, and any identically named properties set in the new profile would override those from the included profile. Kind of like if a subclass is shadowing a field from the superclass, any instance of the subclass would reflect the shadowed value. Here's the file:

spring:
  profiles: foo
name: foo

--- # New YAML doc starts here

spring:
  profiles: 
    include: foo
  profiles: bar
name: bar

If I run this in a test case with the "bar" profile explicitly activated, the name property will still be foo:

SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
SpringApplication app = builder.application();
builder.profiles("bar");
ConfigurableApplicationContext ctxt = app.run();
String name = ctxt.getEnvironment().getProperty("name"); // Is always "foo" much to my surprise

However, if I comment out the include:

spring: 
profiles: bar
#  profiles: 
#    include: foo

and activate the two profiles explicitly in my code:

builder.profiles("foo", "bar");

Then it works as I would expect, and the name property is set to bar. The main reason I would rather handle the includes in the YAML files is that it's less impact on my actual code, and I can manage all profile inclusion in one place. With the other approach, I'd have to search for profile strings and possible @Profile annotations in my entire project if I were to ever rename the profiles. That's definitely more error prone. I think a more flexible solution would be to explicitly be able to express whether or not the included profile overrides the sub profile values or not. Maybe something like:

spring:
  profiles: bar
  profiles:
    include: foo
      override: false

Maybe I'm just missing something here. Is there a better way of doing this? Thanks.

user2337270
  • 1,183
  • 2
  • 10
  • 27
  • 1
    The function of `spring.profiles.include` is to affect the `Environment.getActiveProfiles()` so that's how you should test the outcome. You appear to be testing with a property key that is present in both profiles (the last one to be applied wins, and it's probably "bar", since that comes last in the YAML). – Dave Syer Sep 23 '14 at 17:36
  • 1
    Thanks for your reply Dave. This is the first time I've heard it explained this way. Reading the Spring Boot reference documentation, this certainly isn't clear (at least not to me). I think that section needs to be clarified, ideally with an example. Thanks. – user2337270 Sep 24 '14 at 22:42
  • Contributions always gratefully accepted. I'm not clear yet on what the clarification would be though. – Dave Syer Sep 25 '14 at 06:11
  • 1
    Thanks Dave. I'll try to whip something together in my not so copious spare time :-) I guess my surprise was that the include I specified actually "shadowed" the values from the profile that specified the include. In my mind I was thinking of it kind of like subclassing and overriding methods in the "subclass" profile. I thought of the include as the base class providing some values, and that the "subclass profile" that included it, would override/shadow property values provided by the "superclass" profile. – user2337270 Sep 26 '14 at 02:47
  • 1
    I made the same mistake, at least that's what my tests are showing. Your YAML is incorrect; specifying two "spring:profiles:" YAML nodes causes the second node to overwrite the first. The "bar" in your last snippet is effectively ignored. If there is some way to make a YAML node both a scalar and a collection, I'm not aware of it, and would gladly welcome corrections. The Note in http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-adding-active-profiles is a terrible way of saying that "spring.profiles.include" won't work in a profile-specific YAML document. – Emerson Farrugia Jan 09 '15 at 12:34
  • To get what you need, you'd need the second doc in this Gist https://gist.github.com/emersonf/11c886e409b1ad7a2b23, which isn't pretty because fragments the profile definition. @DaveSyer, think I should file this as an issue, at least the doc improvement? – Emerson Farrugia Jan 09 '15 at 12:39
  • Sure. Let'f fix the docs. – Dave Syer Jan 09 '15 at 17:22

1 Answers1

6

Try the following for foo to include but override bar, seems to be working for my solution

spring:
    profiles:
        include: bar
        active: foo,bar

edit: please mind, that it's a "hack", not officially supported and it's for 2016 version

dpedro
  • 1,397
  • 1
  • 9
  • 8
  • Nice @dpedro! I hadn't thought of explicitly setting several profiles as active like that. That solved my problem. – user2337270 Jan 24 '16 at 20:26
  • @ArchimedesTrajano it's possible. Note, that there might have been changes in Spring Boot and this solution (hack, really) is for version from 2 years ago – dpedro Jan 17 '18 at 12:09
  • 1
    include and active both supports multiple values. properties present in Last one overrides for the keys present in previous ones. Usually these kind of informations are missing in spring.io documentation. – pramodc84 Apr 24 '18 at 11:16
  • This "workaround" no longer seems applicable as of (at the very least, likely earlier) Spring Boot `2.3.7.RELEASE`. In my case I had to rework my profiles so that my default values are more generic (e.g. `spring.datasource.url: jdbc:postgresql://${host}/{$database}`), and are then specifically overridden in the profiles - i.e. the "normal" way. I imagine the groupings could be cleaned up a bit more using profile groups once we switch to `>=2.4.0.RELEASE`. This is obviously unfortunately not applicable in all cases, but should be fine if your infrastructure is clean-ish across the board. YMMV. – filpa Nov 17 '21 at 11:07