Search code examples
javaspringspring-java-config

Decide which JavaConfig class to load at runtime


There are multiple classes annotated with @Configuration and I want to decide in a top-level config component which one to register in the context.

@Configuration
public class FileSystemDataStoreConfiguration {
  public @Bean DataStore getDataStore() {
    return new FileSystemDataStore(withSomeConfigProperties);
  }
}

@Configuration
public class DatabaseDataStoreConfiguration {
  public @Bean DataStore getDataStore() {
    return new DatabaseDataStore(withSomeConfigProperties);
  }
}

@Configuration
public class DataStoreConfiguration {

  // Some arbitrary logic to decide whether I want to load
  // FileSystem or Database configuration.

}

I understand that I can use @Profile to select among multiple configuration classes. However, I already use profiles to distinguish between environments. The selection of the configuration classes is indepedent from the environment.

How can I select at runtime which configuration class to load?

Can I have multiple active profiles like "Production, WithDatabase"?

If so, how can I add a profile based on a property?


Solution

  • Spring, so there are lots of ways to do things!

    If you stay all annotations, you can use the @ActiveProfiles annotation so enable the overall set of profiles you want:

    @ActiveProfiles(profiles = ProfileDefinitions.MY_ENABLED_PROFILE)
    @ContextConfiguration(as usual from here...)
    

    You see the "profiles" allows many profiles to be set. You don't need to store the profiles as constants either, but you may find that helpful:

    public class ProfileDefinitions {
    
        public static final String MY_ENABLED_PROFILE = "some-profile-enabled";
    
        // you can even make profiles derived from others:
        public static final String ACTIVE_WHEN_MY_IS_NOT = "!" + MY_ENABLED_PROFILE;
    }
    

    Using all of the above, you can selectively enable various configurations based upon the dynamic setting of the Profiles:

    @Profile(ProfileDefinitions.MY_ENABLED_PROFILE)
    @Configuration
    @Import({these will only be imported if the profile is active!})
    public class DatabaseDataStoreConfiguration {
    }
    
    @Profile(ProfileDefinitions.ACTIVE_WHEN_MY_IS_NOT)
    @Configuration
    @Import({if any are necessary})
    public class DataStoreConfiguration {
    }