Reputation: 47
Here's my code:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import java.util.List;
@Configuration
public class ResourceTest {
@Bean
TestBean testBean () {
return new TestBean();
}
@Bean
TargetBean targetBean () {
return new TargetBean("bean1");
}
@Bean(name = "myBean")
TargetBean targetBean2 () {
return new TargetBean("bean2");
}
@Bean(name = "myBean")
TargetBean targetBean3 () {
return new TargetBean("bean3");
}
public static void main (String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ResourceTest.class);
TestBean bean = context.getBean(TestBean.class);
System.out.println(bean.getTargetBeanList());
}
public static class TestBean {
private List<TargetBean> targetBeanList;
@Resource(name = "myBean")
public void setXList (List<TargetBean> targetBeanList) {
this.targetBeanList = targetBeanList;
}
public List<TargetBean> getTargetBeanList () {
return targetBeanList;
}
}
public static class TargetBean {
private final String str;
public TargetBean (String str) {
this.str = str;
}
public String getStr () {
return str;
}
@Override
public String toString () {
return "TargetBean{ str='" + str + '\'' +
'}';
}
}
}
Output: [TargetBean{ str='bean2'}]
Expected: All beans qualifying "myBean" should be in the list i.e. bean2 and bean3.
According to spring ref docs:
Qualifiers also apply to typed collections, as discussed above, for example, to Set. In this case, all matching beans according to the declared qualifiers are injected as a collection. This implies that qualifiers do not have to be unique; they rather simply constitute filtering criteria. For example, you can define multiple MovieCatalog beans with the same qualifier value "action", all of which would be injected into a Set annotated with @Qualifier("action").
I'm using Spring 4.3.2.RELEASE. Please help fixing this. Thanks in advance.
Upvotes: 1
Views: 5898
Reputation: 279970
The name
in a @Bean
annotated element represents the corresponding bean definition's identifier. If you have two bean definitions with the same id, the one registered later overwrites the previous one. That's what happens with your beans here
@Bean(name = "myBean")
TargetBean targetBean2 () {
return new TargetBean("bean2");
}
@Bean(name = "myBean")
TargetBean targetBean3 () {
return new TargetBean("bean3");
}
You've linked that part of the doc but you're not doing any of the things it says.
For example, you can define multiple
MovieCatalog
beans with the same qualifier value "action"
Let's adapt that to your beans
@Bean(name = "myBean2")
@Qualifier("myBean")
TargetBean targetBean2() {
return new TargetBean("bean2");
}
@Bean(name = "myBean3")
@Qualifier("myBean")
TargetBean targetBean3() {
return new TargetBean("bean3");
}
Notice they have different ids (you can omit the @Bean
annotation and Spring will use the method name) but are using the same @Qualifier
value.
Then
all of which would be injected into a Set annotated with
@Qualifier("action")
At your injection point, use that
@Autowired
@Qualifier("myBean")
public void setXList(List<TargetBean> targetBeanList) {
this.targetBeanList = targetBeanList;
}
targetBeanList
will now contain the two TargetBean
beans that were qualified with myBean
.
Spring resolves @Resource
by using the name
provided to lookup a bean by name. It has no knowledge of @Qualifier
values. That's why we use @Autowired
with @Qualifier
above.
Upvotes: 7
Reputation: 47
Thanks to Sotirios Delimanolis for helping me to fix the problem.
To summarize my understanding:
(1)The 'name' element in @Bean(name = ....) is an identifier not a qualifier. It may work with matching qualifier (the injection points where we use @Autowired along with @Qualifier or with @Resource) but not in my case as ids cannot be declared same.
(2)The true qualifier is declared with @Qualifier annotation which can be used along with @Bean methods, @Component (classes), and along with @Autowired (the injection points).
I guess, when it comes to matching/filtering beans by some name we should always use @Qualifier i.e. never rely on (1).
Btw I wanted to put as comment to the above reply.. but for some reasons it's not accepting that.. ;)
Upvotes: 0