How to inject different services at runtime based on a property with Spring without XML



I am using Spring Boot for Java standalone application. I have a bean which makes use of a service. I want to inject different implementations of that service at runtime, based on a property in a properties file with Spring (4 for that matter).




This sounds like the Factory pattern, but Spring also allows using annotations to solve the problem, like this.



@Autowired @Qualifier("selectorProperty") private MyService myService;


Then in the beans.xml file I have an alias, so that I can use the property in the @Qualifier.



<alias name="${selector.property}" alias="selectorProperty" />


And in my different implementations I would have different qualifiers.



@Component("Selector1")
public class MyServiceImpl1

@Component("Selector2")
public class MyServiceImpl2


application.properties



selector.property = Selector1

selector.property = Selector2




Whereas regarding the factory pattern, in Spring you can use ServiceLocatorFactoryBean to create a factory that would give you the same functionality.



<bean
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean"
id="myServiceFactory">
<property
name="serviceLocatorInterface"
value="my.company.MyServiceFactory">
</property>
</bean>

public interface MyServiceFactory
{
MyService getMyService(String selector);
}


And then in your bean you can use something like this to get the right implementation at runtime depending on the value of the property.



@Value("${selector.property}") private String selectorProperty;

@Autowired private MyServiceFactory myServiceFactory;

private MyService myService;

@PostConstruct
public void postConstruct()
{
this.myService = myServiceFactory.getMyService(selectorProperty);
}


But the problem with this solution is that I could not find a way to avoid using XML to define the factory, and I would like to use only annotations.




So the question would be, is there a way to use the ServiceLocatorFactoryBean (or something equivalent) using only annotations, or am I forced to use the @Autowired @Qualifier way if I do not want to define beans in XML? Or is there any other way to inject different services at runtime based on a property with Spring 4 avoiding XML? If your answer is just use the @Autowired @Qualifier with the alias, please give a reason why that is better than using a well known factory pattern.


Using the extra XML is forcing me to use @ImportResource("classpath:beans.xml") in my Launcher class, which I'd rather not use either.


Thanks.


No comments:

Post a Comment