6

I have a service interface

interface ImageSearchService {
   // methods...
}

And I have 2 implementations:

@Service
class GoogleImageSearchImpl implements ImageSearchService {
   // methods...
}

@Service
class AzureImageSearchImpl implements ImageSearchService {
   // methods...
}

And I have a controller to use one of the both:

@Controller
ImageSearchController {

    @Autowired
    ImageSearchService imageSearch; // Google or Azure ?!?

}

How can I use a Environment API to set the right one implementation?

If environment property is my.search.impl=google spring needs to use GoogleImageSearchImpl, or if environment my.search.impl=google spring needs to use AzureImageSearchImpl.

Beto Neto
  • 3,962
  • 7
  • 47
  • 81

2 Answers2

11

You can achieve this using Spring Profiles.

interface ImageSearchService {}

class GoogleImageSearchImpl implements ImageSearchService {}

class AzureImageSearchImpl implements ImageSearchService {}

Note that the @Service annotation has been removed from both the implementation classes because we will instantiate these dynamically.

Then, in your configuration do this:

<beans>
  <beans profile="azure">
    <bean class="AzureImageSearchImpl"/>
  </beans>
  <beans profile="google">
    <bean class="GoogleImageSearchImpl"/>
  </beans>
</beans>

If you use Java configuration:

@Configuration
@Profile("azure")
public class AzureConfiguration {
  @Bean
  public ImageSearchService imageSearchService() {
    return new AzureImageSearchImpl();
  }
}

@Configuration
@Profile("google")
public class GoogleConfiguration {
  @Bean
  public ImageSearchService imageSearchService() {
    return new GoogleImageSearchImpl();
  }
}

When running the application, select the profile you want to run as by setting the value for the variable spring.profiles.active. You can pass it to the JVM as -Dspring.profiles.active=azure, configure it as an environment variable, etc.

Here is a sample application that shows Spring Profiles in action.

manish
  • 19,695
  • 5
  • 67
  • 91
  • 5
    You can just put `@Profile` on your `@Service` bean and then it will be only loaded the desired environment. Is easier then creating configuration classes or xml files for it... – M. Deinum Feb 24 '15 at 15:45
  • Thanks @Marten, that is definitely much simpler. – manish Feb 24 '15 at 15:47
  • @M.Deinum, can I define a default profile when there is no one setted? – Beto Neto Feb 24 '15 at 16:16
  • 1
    Yes, there is a default profile called `default`. You can use one of your implementations as the default as `@Profile({ "azure", "default" }) @Service class AzureImageSearchImpl {}` or provide a completely different default implementation as `@Profile("default") @Service class DummyImageSearchImpl {}`. – manish Feb 24 '15 at 16:24
0

You can use @Conditional also

@Configuration
public class MyConfiguration {

  @Bean
  @Conditional(LinuxCondition.class)
  public MyService getMyLinuxService() {
    return new LinuxService();
  }
}

Example given : Spring choose bean implementation at runtime

Abhishek Chatterjee
  • 1,962
  • 2
  • 23
  • 31