Howdy there, I've a couple of questions for Spring experts here.
Let's say I have a service interface, for example a very simple one like this:
and different implementations I want Spring to treat as @Services:
I want to know how I could select, at runtime, which concrete implementation to use. In another @Service or @Component annoted class I could autowire directly an instance of ISmartService this way, provided that there's no ambiguity on which concrete class to inject:
First of all, I wonder if autowiring interfaces is a good practice or not in Spring: generally speaking, working with interfaces and avoid coupling with concrete classes is a good design practice (when it's possibile, of course), but I've read somewhere that in Spring using interfaces instead of concrete beans isn't a good habit.
Honestly, I don't understand why.
Second: to avoid ambogous bean referencing, I need to specify which is the default implementation of ISmartService I want to use. To achieve this, I thought to use a @Configuration class defined this way:
If I had not a @Primary factory defined, Spring fx would complain because it would not be able to choose which implementation to inject. I choose to use a @Configuration class, but I don't know if it's a good practice or not to mark as @Primary a bean producer method.
Third - and last question at the moment :-) - : what's the best or more largely used strategy to select which implementation to use ?
Two options came to my mind: the first option is to use profiles. I could run separated instances of my program and select concrete implementations on an active profile basis.
The second option is to implement an SPI based solution: i could annotate each service with a custom annotation, for example @Standard and @Custom, and let my program act this way: if an implementation marked as @Custom is present in the classpath, then inject it; otherwise, inject the standard implementation.
What are you suggestions, guys ?
Thanks for your help in advance.
You can put @Primary on a class as well, no need to use an @Configuration class for that.
There are two ways I can think of to get non-primary bean instances:
1) Inject a List<ISmartService>. Spring will find all implementations. You can then select anything you want from this list.
2) Use qualifiers. Both the provider (the class or @Bean method) and the lookup (the autowired field / constructor argument / ...) must use the same qualifier. I'm not sure if this has the power of CDI's Instance's select method, where you can do a lookup directly on an injected Instance.
I've tried with further tests. Looks like that using SPI is necessary, at least if you want to instantiate beans definited in "pluggable" jars. Anyway I think that Rob's suggestion, i.e inject a list of all available service of a given type, it's the most straightforward approach when all bean are co-located in the same spring project.