Reputation: 20189
I have a Spring component defined like this:
@Component
public class SearchIndexImpl implements SearchIndex {
IndexUpdater indexUpdater;
@Autowired
public SearchIndexImpl(final IndexUpdater indexUpdater) {
Preconditions.checkNotNull(indexUpdater);
this.indexUpdater = indexUpdater;
}
}
along with two implementations of the IndexUpdater
interface, like:
@Component
public class IndexDirectUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
@Component
public class IndexQueueUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
If I try to auto-wire SearchIndexImpl
like this:
@Autowired
private SearchIndex searchIndex;
I get the following exception:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'IndexUpdater' available: expected single matching bean but found 2: indexDirectUpdater,indexQueueUpdater
which is expected since Spring cannot tell which IndexUpdater
implementation to auto-wire for the indexUpdater
parameter in the constructor of SearchIndexImpl
. How do I guide Spring to the bean that it should use? I understand I can use the @Qualifier
annotation, but that will hard-code the index updater to one of the implementation, while I want the user to be able to specify what index updater to use. In XML, I can do something like:
<bean id="searchIndexWithDirectUpdater" class="SearchIndexImpl">
<constructor-arg index="0" ref="indexDirectUpdater"/>
</bean>
How do I do the same using Spring's Java annotations?
Upvotes: 0
Views: 549
Reputation: 131346
Use the @Qualifier
annotation to specify the dependency to use :
public SearchIndexImpl(@Qualifier("indexDirectUpdater") IndexUpdater indexUpdater) {
Preconditions.checkNotNull(indexUpdater);
this.indexUpdater = indexUpdater;
}
Note that @Autowired
is not needed to autowire the arg constructor of a bean since Spring 4.
To answer to your comment.
To let the class that will use the bean to define the dependency to use you could allow it to define the IndexUpdater
instance to inject in the container such as :
// @Component not required any longer
public class IndexDirectUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
// @Component not required any longer
public class IndexQueueUpdater implements IndexUpdater, DisposableBean, InitializingBean {
}
Declare the bean in a @Configuration class :
@Configuration
public class MyConfiguration{
@Bean
public IndexUpdater getIndexUpdater(){
return new IndexDirectUpdater();
}
The SearchIndexImpl
bean will now resolve the dependency thanks to IndexUpdater getIndexUpdater()
.
Here we use @Component
for one bean and @Bean
for its dependency.
But we could also allow a full control on the beans to instantiate by using only @Bean
and by removing @Component
on the 3 classes :
@Configuration
public class MyConfiguration{
@Bean
public IndexUpdater getIndexUpdater(){
return new IndexDirectUpdater();
}
@Bean
public SearchIndexImpl getSearchIndexFoo(){
return new SearchIndexImpl(getIndexUpdater());
}
Upvotes: 1