spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.19k stars 37.96k forks source link

Review Default Profile section in the reference documentation #30319

Closed manueljordan closed 9 months ago

manueljordan commented 1 year ago

In the current reference documentation exists the Default Profile section. It has the following content

Starting with a code:

@Configuration
@Profile("default")
public class DefaultDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .build();
    }
}

and the following content/explanation:

If no profile is active, the dataSource is created. You can see this as a way to provide a default definition for one or more beans. If any profile is enabled, the default profile does not apply.

You can change the name of the default profile by using setDefaultProfiles() on the Environment or, declaratively, by using the spring.profiles.default property.

Therefore: Why from the beginning was not used directly spring.profiles.active? - it especially taking in consideration that is known that spring.profiles.active has more precedence and overrides by complete spring.profiles.default as indicated in bold above.

As summary:

Is not clear when is mandatory use the former over the latter - and taking the special consideration about the behavior of overriding if the latter is declared.

Just in case, the @Profile javadoc does not contain some indication about this

I create a post on SO at:

But I think the explanation from the source (here) should be expanded. Thanks for your understanding

quaff commented 1 year ago

It's not clear what will happen if both spring.profiles.active and spring.profiles.default are provided, I suspect that spring.profiles.default is ignored if spring.profiles.active present. And what's the differences between @Profile("default") and absence of @Profile?

snicoll commented 9 months ago

I don't understand the problem to be honest.

spring.profile.default defines the name of the default profile(s). That doc states as much:

The name of the default profile is default. You can change the name of the default profile by using setDefaultProfiles() on the Environment or, declaratively, by using the spring.profiles.default property.

So if you set it, you just change the name of the default profile. This doesn't do anything else as described above.

if both spring.profiles.active and spring.profiles.default are provided, I suspect that spring.profiles.default is ignored if spring.profiles.active present.

If you customize the name of the default profile and the you active a profile explicitly, those two things are unrelated. As already stated in the doc, activating a profile means that the default profile fallback does not apply.

And what's the differences between @Profile("default") and absence of @Profile?

That's also unrelated. If you don't have a profile at all, beans are always created. If you have a profile that matches the name of the default profile, it's considered only if no profile is active.

I've polished the section a bit with an explicit link to what it means to activate a profile. If you want to refine, feel free to submit a PR and we can continue the conversation.

quaff commented 9 months ago

It seems that spring.profiles.default can do everything we need, why there is another spring.profiles.active?

snicoll commented 9 months ago

Default only set a name to use as a fallback. It’s a mechanism to allow you to enable a profile if no other profile is active. Active predates support for default profile. These are not the same as, as soon as you want certain profiles to he enabled, the default won’t be.

I am sorry but I don’t know where the confusion comes from.

quaff commented 9 months ago

For example, if we defined profile foobar, then there are two profiles : foobar and implicit default, if we want to activate foobar, we could set spring.profiles.default=foobar, no need for spring.profiles.active=foobar, that means spring.profiles.active is not necessary.

bclozel commented 9 months ago

I don't think this discussion is going anywhere.

Making the case that spring.profiles.active is useless in some cases and that spring.profiles.default is enough does not mean that it's not useful. You've just shown that sometimes, technically, it's not needed. We could also make the opposite argument: we could enforce that Spring Framework does not let you change the default profile (always set as "default") and you should only use spring.profiles.active.

Let's say a company ships a product "myproduct" with customizations for "customerA" and "customerB" that are enabled by Spring profiles. Beans for the vanilla product should be named "default" if we want them to be contributed to the app, unless a "customerA" or "customerB" profile is chosen by the user. It would be nice to have those named "myproduct" as "default" is really generic. If we remove this possibility, developers would rightfully complain that:

quaff commented 9 months ago

I'm not saying current design is problematic, I'm saying it confuse people like me. I suggest the document should be revised to state that both spring.profiles.active and spring.profiles.default could activate profiles and the former is recommended, and share a real use case of spring.profiles.default.

rossapi commented 6 months ago

Hope below analysis would help ( even though it's closed now ) if you consider a real prod-ready case , for example in docker env. say you have 3 env, dev, qa, sat, prod and by default dev should be used ( which also can be changed from arguments by external value )

  1. you may need to pass qa to DOCKER_BUILD_ENV for qa testing build
  2. you may need to pass sat to DOCKER_BUILD_ENV or sat build
  3. you may need to pass prod to DOCKER_BUILD_ENV or prod build
  4. you may not need to pass anything to this var in the local docker build or anywhere not applied in the entrypoint var or env var dev profile will be the fallback moreover SRE/DevOps may pass a different value into a more complex env for this DOCKER_DEFAULT_ENV e.g you docker file may look like this example ENTRYPOINT ["java", "-Dspring.profiles.active=${DOCKER_BUILD_ENV}", "-Dspring.profiles.default=${DOCKER_DEFAULT_ENV}", "-jar", "/testapp.jar"] in this case. SRE gains full control of potential changes of default profile or build profile precisely programmatically , if only using one of active or default. say you only get to set DOCKER_DEFAULT_ENV but spring.profiles.active could be in system level variables ( jvm var can also be the case ).

In short. applying precise spring.profiles.active and spring.profiles.default let 'external team' to external control precisely