1

I have a component EmbeddedRedis that depends on a configuration object RedisConfig parsed from the application's property file. There are different property files, corresponding to the possible application profiles that can be run. Thus, when run in profile master, the component EmbeddedRedis will be provisioned according to the master profile.

In a test class, that is supposed to set-up a local Redis cluster, I also require Redis objects provisioned according to all other profiles. I sketched my idea below using the @Qualifier annotation, which does not bring the desired result.

@Autowired @Qualifier("dev-cluster-master")
private Redis embeddedRedisMaster;

@Autowired @Qualifier("dev-cluster-slave-001")
private Redis embeddedRedisSlave1;

@Autowired @Qualifier("dev-cluster-slave-002")
private Redis embeddedRedisSlave2;

How can I archive the desired result in Spring Boot? If that doesn't work directly, would it also suffice to obtain the before-mentioned configuration objects parsed from the different property files.

@Component
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfig {
 ....
}

Thanks in advance!

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
twiechert
  • 83
  • 1
  • 7

3 Answers3

3

You can do something like this: Consider you have a class definition (Redis in your example)

public class CustomService {

    private String name;

    public CustomService(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

And a configuration class like:

@Configuration
public class Config {

    @Bean
    @Profile("master")
    CustomService serverConfig1(){
        CustomService service1 = new CustomService("master");
        return service1;
    }

    @Bean
    @Profile("slave")
    CustomService serverConfig2(){
        CustomService service1 = new CustomService("slave");
        return service1;
    }
}

which initiate 2 different objects based on current active profile. If current active profile is "master", then serverConfig1() will get executed, otherwise serverConfig2().

And finally autowired your service/object like this:

@Autowired
CustomService service;

This will depends on above executed bean definition in configuration file.

And property file should look like this:

spring.profiles.active=slave

So in this example, after executing above code, the value of 'name' in CustomService service; will be "slave" instead of "master", because current active profile is "slave" and thus "serverConfig2()" will get executed

Afridi
  • 6,753
  • 2
  • 18
  • 27
  • Hi Afridi, thanks for your answer but I don't quite understand it. The code snippet does not even compile, because the @Profile annotation is not applicable to fields. – twiechert May 09 '17 at 13:01
  • Oh sorry, @Profile("master") annotation can be only used with method not with fields. So this annotation should be added on method of your bean definition for Redis. So can you post your bean definitions for each of the Redis configuration?? after than spring will initialize specific bean on the basis of active profile – Afridi May 09 '17 at 13:15
  • "after than spring will initialize specific bean on the basis of active profile" - I need multiple components, each provisioned with a different profile. So annotating the bean definition won't solve my problem. – twiechert May 09 '17 at 13:53
  • 1
    Basically, you explained how the general profile mechanism works, which I'm however aware of and not require here. I need multiple instances of this component built according to different profiles at **the same runtime**. – twiechert May 09 '17 at 14:18
  • do you mean that there is a many-to-many relationship between active profiles and instances of given object(Redis)?? that is for a given profile, there can be multiple different instances. If so, then you can use Qualifier along with Profile annotation – Afridi May 09 '17 at 14:42
  • No, one profile maps to one instance. But I need multiple profiles being active and one instance per active profile, i.e. one Redis instance for the "dev-cluster-master", ""dev-cluster-slave-001" ... profile. – twiechert May 09 '17 at 14:47
  • 1
    then still you have to use both Qualifier along with Profile. So then if you have 2 active profiles, spring will load both instances, otherwise the one that is currently active – Afridi May 09 '17 at 14:54
2

You can do something like this: Consider you have an interface definition:

public interface SomeService {
    String someMethod;
}

And two implemented class:

@Profile("production")
@Service
public class SomeServiceProd implements SomeService {
     @Override String someMethod() {return "production";}
}

@Profile("development")    
@Service
public class SomeServiceProd implements SomeService {
     @Override String someMethod() {return "development";}
}

And use this service in test and main code:

@Autowired SomeService service;
1

If you need your component only with certain profile and you don't want to or can't create a common interface you could inject like this:

@Autowired
    private Optional< Redis > redis;

You would have to check if present on each different object on every profile.

If you share a common interface use the other answer solution to create different beans implementing the interface per each profile.

dhalfageme
  • 1,444
  • 4
  • 21
  • 42