英文:
Spring Bean annotation: why only one Qualifier is needed for several beans of the same type
问题
Dog.java:
@Component
public class Dog {
@Autowired
@Qualifier("dogName")
public String dogNameop;
public Dog() {
}
public Dog(String dogNameop) {
this.dogNameop = dogNameop;
}
public String getDogNameop() {
return dogNameop;
}
public void setDogNameop(String dogNameop) {
this.dogNameop = dogNameop;
}
}
Cat.java:
@Component
public class Cat {
private String catName;
public Cat() {
}
@Autowired
public Cat(String catName) {
this.catName = catName;
}
public String getCatName() {
return catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
}
Bear.java:
@Component
public class Bear {
private String bearName;
public Bear() {
}
@Autowired
public Bear(String bearName) {
this.bearName = bearName;
}
public String getBearName() {
return bearName;
}
public void setBearName(String bearName) {
this.bearName = bearName;
}
}
Config.java:
@Configuration
public class Config {
@Bean
String dogName() {
return "oof";
}
@Bean
String catName() {
return "catto";
}
@Bean
String bearName() {
return "bear";
}
}
DemoApplication.java:
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
CommandLineRunner commandLineRunner(Dog dog, Cat cat, Bear bear) {
return args -> {
System.out.println(dog.dogNameop);
System.out.println(cat.getCatName());
System.out.println(bear.getBearName());
};
}
}
Output:
oof
catto
bear
如果我从 Dog.java
中删除 @Qualifier("dogName")
,我会得到错误:
Field dogNameop in com.example.demo.Dog required a single bean, but 3 were found:
然而,只有一个限定符,它可以正确地分配到 Cat
和 Bear
类中。怎么做到的?我会期望每个类:Dog
、Cat
和 Bear
都需要一个 @Qualifier
注解。
编辑:
在 Cat
类中将字段名称从 catName
更改为 catNameHm
会再次出现错误(将 Bear
类中的 bearName
更改为 bearNameOh
也会触发错误)。
看起来一旦应用了单个 @Qualifier
,它会使Spring始终通过字段名称对类型为 String
的自动装配进行应用 - 在所有类中,而不仅仅是具有 @Qualifier
注解的类吗?
英文:
Dog.java:
@Component
public class Dog {
@Autowired
@Qualifier("dogName")
public String dogNameop;
public Dog() {
}
public Dog(String dogNameop) {
this.dogNameop = dogNameop;
}
public String getDogNameop() {
return dogNameop;
}
public void setDogNameop(String dogNameop) {
this.dogNameop = dogNameop;
}
}
Cat.java:
@Component
public class Cat {
private String catName;
public Cat() {
}
@Autowired
public Cat(String catName) {
this.catName = catName;
}
public String getCatName() {
return catName;
}
public void setCatName(String catName) {
this.catName = catName;
}
}
Bear.java:
@Component
public class Bear {
private String bearName;
public Bear() {
}
@Autowired
public Bear(String bearName) {
this.bearName = bearName;
}
public String getBearName() {
return bearName;
}
public void setBearName(String bearName) {
this.bearName = bearName;
}
}
Config.java:
@Configuration
public class Config {
@Bean
String dogName() {
return "oof";
}
@Bean
String catName() {
return "catto";
}
@Bean
String bearName() {
return "bear";
}
}
DemoApplication.java:
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
CommandLineRunner commandLineRunner(Dog dog, Cat cat, Bear bear) {
return args -> {
System.out.println(dog.dogNameop);
System.out.println(cat.getCatName());
System.out.println(bear.getBearName());
};
}
}
Output:
oof
catto
bear
If I remove @Qualifier("dogName")
from Dog.java
, I get the error:
Field dogNameop in com.example.demo.Dog required a single bean, but 3 were found:
However with only one qualifier it manages to correctly assign the fields in Cat
and Bear
classes. How? I would expect that each class: Dog
, Cat
, and Bear
would require a @Qualifier
inside.
EDIT:
Changing the field name in Cat
from catName
to catNameHm
makes the error to appear again (independently chaning bearName
in Bear
class to bearNameOh
also triggers the error).
So it looks like once a single @Qualifier
is applied it makes Spring to always apply autowiring of type String
by the name of the field - in all classes, rather than just the class that has @Qualifier
annotation?
答案1
得分: 2
Spring解决了依赖注入的问题因为:
-
@Bean
方法名是默认的bean名称。
Baeldung:当我们在方法上使用 @Bean 注解时,Spring 使用方法名作为 bean 名称。
-
如果没有指定限定符并且同一类的多个bean可用,Spring
@Autowire
会回退到参数名作为限定符。
Baeldung(请参考引用后的示例):Spring 使用 bean 的名称作为默认限定符值。
官方文档:
对于回退匹配,bean 名称被视为默认限定符值。因此,您可以使用
main
作为bean的ID,而不是嵌套的限定符元素,从而导致相同的匹配结果。
因此,为了解决 @Autowired public Bear(String bearName)
,Spring 查找名为 bearName
的bean,这是由于定义函数命名而存在的。对于 catName
也是类似的。
英文:
Spring resolves that dependency injection because:
@Bean
method name is the default bean name.
Baeldung:
> when we use the @Bean annotation on a method, Spring uses the method
> name as a bean name.
- If no qualifier is specified and multiple beans of a same class are available, Spring
@Autowire
falls back to parameter name as a qualifier.
Baeldung (see example after quote):
> Spring uses the bean's name as a default qualifier value
> For a fallback match, the bean name is considered a default qualifier
> value. Thus, you can define the bean with an id of main instead of the
> nested qualifier element, leading to the same matching result.
Thus, to resolve @Autowired public Bear(String bearName)
Spring looks up for a bean named bearName
, which is present due to defining function naming. Likewise for catName.
答案2
得分: 1
Spring解决依赖注入的动机在于如何解析依赖。
Spring可以通过类型、名称或显式限定符来解析依赖关系。由于所有三个bean都是字符串,Spring框架解析依赖注入的唯一方式是通过名称或@Qualifier。
这就是为什么你必须添加@Qualifier,否则你可能需要考虑重构你的类,并将dogNameop
改为dogName
,如下所示:
@Component
public class Dog {
@Autowired
@Qualifier("dogNameop")
public String dogName;
public Dog() {
}
public Dog(String dogName) {
this.dogName = dogName;
}
public String getDogName() {
return dogName;
}
public void setDogName(String dogName) {
this.dogName = dogName;
}
}
英文:
Motivation around is about how Spring resolves the dependency injection.
Spring can resolve via type, name or explicit qualifier. Since all three beans are Strings, the only way for SprinfFramework can resolve the dependency injection is via name or @Qualifier
that's way you have to put the @Qualifier otherwise you can evaluate to refactor your class and change dogNameop to dogName like below:
@Component
public class Dog {
@Autowired
public String dogName;
public Dog() {
}
public Dog(String dogName) {
this.dogName = dogName;
}
public String getDogName() {
return dogName;
}
public void setDogName(String dogName) {
this.dogName = dogName;
}
}
答案3
得分: 1
-
你正在使用
@Autowire
注入一个String
。所以,在你的应用程序上下文中,有三个这种类型的 bean。
-
Spring 必须进行选择,因为你正在注入一个单个的 bean,但没有限定符,Spring 无法进一步缩小搜索范围。
故事结束:出现错误。
注意: 如果你想要所有类型为
String
的 bean,你可以使用@Autowire
注入一个List<String>
,然后自行决定哪一个适合你的需求。
英文:
-
You are
@Autowire
'ing aString
So, in your application context, there are three beans with that type.
-
Spring got to choose, since you're injecting a single bean, but without qualifiers, there is nothing more Spring can do to narrow down the search.
End of the story: error.
> NOTE: If you wanted all beans of type String
, you could @Autowire
on a List<String>
, then decide for yourself which one suits your need.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论