Home > database >  Custom Spring properties files with profile-dependent loading
Custom Spring properties files with profile-dependent loading

Time:10-17

We are currently having one application.properties and one application-staging.properties, which is loaded based on the active Spring profile.

However, it's very bloated and we like to split it into multiple properties files based on the context.

For example:

teams.properties and teams-staging.properties

We load it using the class below

@Getter
@Configuration
@PropertySource("classpath:teams.properties")
public class TeamsProperties {

    @Value("${teams.some-team-a}")
    private String someTeamA;

    @Value("${teams.some-team-b}")
    private String someTeamB;

}

But it won't respect the profile and the teams-staging.properties is ignored.

What would be needed to "clone" the default application.properties behaviour for custom properties files?

CodePudding user response:

@PropertySource accept an array as value. You can do this :

@Getter
@Configuration
@PropertySource({"classpath:teams.properties", "classpath:teams-${spring.profiles.active}.properties"})
public class TeamsProperties {
    
    @Value("${teams.some-team-a}")
    private String someTeamA;
    
    @Value("${teams.some-team-b}")
    private String someTeamB;
    
}

Then run the application with the active profile :

-Dspring.profiles.active=staging

The disadvantage of this solution is that you always have to pass only one active profile. It will not work for multiple profiles : -Dspring.profiles.active=foo,bar

CodePudding user response:

I've decided to do it via inheritance as @xerx593 recommended in the comment.

@Getter
public abstract class TeamsProperties {

    @Value("${teams.some-team-a}")
    private String someTeamA;

    @Value("${teams.some-team-b}")
    private String someTeamB;


    @Configuration
    @Profile({"!staging"})
    @PropertySource({"classpath:teams.properties"})
    public static class TeamsPropertiesDefault extends TeamsProperties {

    }

    @Configuration
    @Profile({"staging"})
    @PropertySource({"classpath:teams-staging.properties"})
    public static class TeamsPropertiesDynamic extends TeamsProperties {

    }

}

The reason is, I'd like to keep teams.properties as the default properties file and only then switch to staging if the profile is staging. I also don't want to have to create one additional .properties file for each profile, like "testing".

So with that way, each profile that is not covered with a specific properties file will always fall back to teams.properties ( but the @Profile annotation of the default must be enhanced of course)

Putting it all together with inner classes keeps it relatively clean and I can live with it.

  • Related