70

I am just wondering what the order of precedence is when multiple Spring active profiles have been specified.

Say I want the default profile to be active but the dev profile to override it when there are several identical elements (beans for instance) to choose from but with different profiles...

Say for instance I have two PropertySourcesPlaceholderConfigurer beans configured with "default" and "dev" values a environment profiles.

If I use the following profile activation: -Dspring.profiles.active="default,dev"

Will the dev profile override the default one?

If not how can the above behavior be achieved?

balteo
  • 23,602
  • 63
  • 219
  • 412
  • 1
    AFAIK, the only "precedence" defined between profiles is based on the declaration order of the beans (just like overriding the definition of any bean), and the last profile-specific bean wins. So if you had a bean with `id="dataSource"` in both profiles, then the last definition of that bean would be used, since the first definition would be overridden by the last. The order of the profiles in `spring.profiles.active` does not actually matter. – superEb May 13 '14 at 01:23

4 Answers4

39

The order of the profiles in the spring.profiles.active system property doesn't matter. "Precedence" is defined by the declaration order of the beans, including beans specific to a profile, and the last bean definition wins.

Using your example, if -Dspring.profiles.active="default,dev" is used, the props bean in the default profile would be used here, simply because it's the last active definition of that bean:

<beans profile="dev">
    <bean id="props" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="location" value="classpath:META-INF/dev.properties"/>
    </bean>
</beans>
<beans profile="default">
    <bean id="props" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
        <property name="location" value="classpath:META-INF/default.properties"/>
    </bean>
</beans>

Invert the order of the beans, and then the dev version would be used, regardless of how the profiles are ordered in spring.profiles.active.

Notice that I did not use <context:property-placeholder/> because it does not allow you to explicitly specify a bean id, and so I'm not sure what behavior it would exhibit if more than one is used. I imagine that the properties would be merged, so that properties defined by both would use the last definition, but properties specific to each file would remain intact.

Otherwise, in my experience, you would typically define beans in this order:

  1. "Default" bean definitions, not specific to a profile
  2. Overriding bean definitions in an environment-specific profile
  3. Overriding bean definitions in a test-specific profile

This way, test profile beans would win if used in combination with other profiles; else you would either use environment-specific beans or default beans based on the profile.

superEb
  • 5,613
  • 35
  • 38
  • 1
    How does it work with classpath scanning? I guess it's not deterministic but it would be great if this or another answer would update this. – musiKk Aug 14 '17 at 06:24
  • @musiKk Good question. With XML files, we can define multiple beans of the same id in the same file, starting with a default and overriding it with a profile-specific bean def later on. With classpath scanning, you'll probably want to use different classes (files) that define the same bean and use the `@Profile` annotation to pick which profile activates the bean. In that case, using a default bean can mean specifying a "default" profile (e.g. `@Profile("default")`) or specifying which profiles *should be absent* (e.g. `@Profile("!dev")`). – superEb Aug 14 '17 at 16:29
  • Sure, there are many approaches but the problem is still the same. Sometimes it's not too easy to create distinct profiles. We recently had this with something like `test,local`, `test,integration`, `local`, `integration`, `live`. I solved it with properties instead of profiles. – musiKk Aug 15 '17 at 13:50
  • using multiple profiles and every profile has different properties file. I will be going to have multiple profiles active at the same point of time. please advice how to NOT OVERRIDE properties in different beans.. – Vrajendra Singh Mandloi Oct 12 '17 at 14:42
  • 2
    @superEb The [springBoot documentation](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-adding-active-profiles) says that the order is important – Prakash K Jun 22 '18 at 15:41
  • 1
    @Prakash I also have doubt over the ordering, I have two different profiles say stage and stage-qa, if property (key) is defined in both the files then the way I am defining spring active profiles matters. If -Dspring.active.profiles=stage,stage-qa then stage-qa takes precedence and if I reverse it then as per ordering it take place. Could you please help me understanding this behavior. – Rahul Singh Sep 29 '18 at 16:36
  • after debugging it seems if we pass _Dspring.profiles.active=stage,stage-qa it does matter which file will have precedence – Rahul Singh Sep 29 '18 at 19:13
  • @PrakashK no, it says nothing about the order, in chapter 2 it defines the order but in different sense e.g. profile specific property file has higher priority over generic one, but that's all... – Betlista Dec 16 '20 at 09:42
  • 1
    It is written in chapter [2.3.3 Profile Specific Files](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-files-profile-specific): "If several profiles are specified, a last-wins strategy applies." – Betlista Dec 16 '20 at 17:11
32

The last definition wins. I keep it in mind but:

It is very important to remember that if you have some default content of application.properties inside jar resources, then this resource content will overwrite entries from external content of less important profiles (other profiles defined earlier in spring.profiles.active).

Example profiles: spring.profiles.active=p1,p2,p3

Files in Jar resources: application-p1.properties and application-p3.properties

External files: application-p1.properties and application-p2.properties

Final order will be (last wins):

  1. resource application.properties
  2. external application.properties
  3. resource application-p1.properties
  4. external application-p1.properties
  5. external application-p2.properties
  6. resource application-p3.properties - HERE IS THE TRICK! this will overwrite properties defined in external files for p1 and p2 with values from resource version of p3
  7. external application-p3.properties

So keep in mind that last wins but also that resource goes just before external

Marek Podyma
  • 913
  • 10
  • 12
  • Is that written in some documentation? I asked similar question some time ago - https://stackoverflow.com/questions/60333056/property-resolving-for-multiple-spring-profiles-yaml-configuration but it is without answer (and it was closed recently). I know, that when I provide `p1,p2` it is at the moment following the order, can I rely on that? – Betlista Dec 16 '20 at 09:46
  • 5
    It is written in chapter [2.3.3 Profile Specific Files](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-files-profile-specific): "If several profiles are specified, a last-wins strategy applies." – Betlista Dec 16 '20 at 17:12
  • I've checked it. `Last-wins` is documented. My post is related to the case when winning profile (the last one) overrides settings from other profiles external settings but with winning profile resource content. BTW, Betlista thank you for reference link. – Marek Podyma Dec 03 '21 at 10:34
11

I had to experiment to convince myself.

Create the most simple spring boot application from Spring Initializr

Then added 3 properties files to resources dir (first one is already there but empty)

# application.properties
foo=foo in application.properties
bar=bar in application.properties
baz=baz in application.properties

# application-foobar.properties
foo=foo in foobar override properties
bar=bar in foobar override properties

# application-barbaz.properties
bar=bar in barbaz override properties
baz=bar in barbaz override properties

Then I added this @Config class to run at startup:

package com.example.profilesexperiment;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
class StartupConfig {

    @Autowired
    private Environment environment;

    @Value("${foo}")
    private String foo;

    @Value("${bar}")
    private String bar;

    @Value("${baz}")
    private String baz;

    @Bean
    CommandLineRunner startup() {
        return args -> {
            System.err.println("Active profiles: " + String.join(", ", environment.getActiveProfiles()));
            System.err.println("Foo = " + foo);
            System.err.println("Bar = " + bar);
            System.err.println("Baz = " + baz);
        };
    }
}

Then I ran it with different combinations of profiles. You can try that yourself, but here are the outputs of some:

just foobar

java -Dspring.profiles.active=foobar -jar target/profiles-experiment-0.0.1-SNAPSHOT.jar   
Active profiles: foobar
Foo = foo in foobar override properties
Bar = bar in foobar override properties
Baz = baz in application.properties

foobar then barbaz

java -Dspring.profiles.active=foobar,barbaz -jar ...
Active profiles: foobar, barbaz
Foo = foo in foobar override properties
Bar = bar in barbaz override properties
Baz = bar in barbaz override properties

barbaz then foobar

java -Dspring.profiles.active=barbaz,foobar -jar ...
Active profiles: barbaz, foobar
Foo = foo in foobar override properties
Bar = bar in foobar override properties
Baz = bar in barbaz override properties

Verdict: clearly, last one wins!

Oh, and also: non-overridden properties merge to one big happy property set (which is the reason I came searching here)

Rhubarb
  • 34,705
  • 2
  • 49
  • 38
8

superEB is right the order of the profiles doesn't matter for beans, the declaration order is more important there, but keep in mind that the order is important if you use profile based configuration files!

Patrick Cornelissen
  • 7,968
  • 6
  • 48
  • 70
  • Does that mean if I use approach described here https://stackoverflow.com/a/48809611/2458858 , and I want to select multiple configurations, I will not be able to? As the last one will override previous ones? Or will they work as there are separate config classes? (assuming I am marking each config as a separate profile) – tryingToLearn Feb 16 '18 at 07:24
  • 3
    If one is using profile-based configuration and multiple per-profile configuration files define the same properties. What's the order of precedence? – Noel Yap May 21 '20 at 14:49
  • 2
    The order is not defined as far as I know, but for this better ask a dedicated Stack overflow question, so that the spring team can also answer if no one else has a good answer – Patrick Cornelissen May 22 '20 at 15:02
  • 1
    It is written in chapter [2.3.3 Profile Specific Files](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-files-profile-specific): "If several profiles are specified, a last-wins strategy applies." – Betlista Dec 16 '20 at 17:11