4

I need to add multiple implementations of an interface and one of them should be picked up based on profile.

For e.g.

interface Test{
    public void test();
}

@Service
@Profile("local")
class Service1 implements Test{
    public void test(){

    }
}

@Service
class Service2 implements Test{
    public void test(){

    }
}


@SpringBootApplication
public class Application {

    private final Test test;

    public Application(final Test test) {
        this.test = test;
    }

    @PostConstruct
    public void setup() {
        test.test();
    }
}

My intention is when I use -Dspring.profiles.active=local then Service1 should be called or else service2 should be called but I am getting an exception that the bean for Test is missing.

Ori Marko
  • 56,308
  • 23
  • 131
  • 233
user1298426
  • 3,467
  • 15
  • 50
  • 96
  • 1
    When asking about an exception, always post the exact and complete error and stack trace. – JB Nizet Apr 29 '19 at 10:35
  • I think you should make two profiles one for Service1 and another for Service2. If you run it with -Dspring.profiles.active=local then both the beans will be created – Mehdi Benmesssaoud Apr 29 '19 at 11:28

2 Answers2

5

Add default profile for Service2:

@Service
@Profile("default")
class Service2 implements Test{
    public void test(){

    }
}

the bean will only be added to the context if no other profile is identified. If you pass in a different profile, e.g. -Dspring.profiles.active="demo", this profile is ignored.

If you want for all profile except local use NOT operator:

@Profile("!local")

If a given profile is prefixed with the NOT operator (!), the annotated component will be registered if the profile is not active

Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • I needed a fake implementation for debugging, so I did `@Primary @Component @Profile("dev")` on it (and setting profile to dev when running locally) – Emiliano Ruiz Jun 02 '22 at 15:38
0

You can add @ConditionalOnMissingBean to Service2 which will means it will only be used in case no other implementation exists, this will effectively make Service2 the default implementation in any other profile other than local

@Service
@ConditionalOnMissingBean
class Service2 implements Test {
    public void test() {}
}
Ahmed Abdelhady
  • 699
  • 3
  • 7
  • There's a caveat, though. The ConditionalOnMissingBean Javadoc says: "The condition can only match the bean definitions that have been processed by the application context so far and, as such, it is strongly recommended to use this condition on auto-configuration classes only." – Petr Gladkikh Jan 24 '23 at 14:14