Spring Bean注解:为什么相同类型的多个bean只需要一个Qualifier。

huangapple go评论76阅读模式
英文:

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:

然而,只有一个限定符,它可以正确地分配到 CatBear 类中。怎么做到的?我会期望每个类:DogCatBear 都需要一个 @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解决了依赖注入的问题因为:

  1. @Bean 方法名是默认的bean名称。
    Baeldung:

    当我们在方法上使用 @Bean 注解时,Spring 使用方法名作为 bean 名称。

  2. 如果没有指定限定符并且同一类的多个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:

  1. @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.

  1. 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

official docs:

> 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

  1. 你正在使用 @Autowire 注入一个 String

    所以,在你的应用程序上下文中,有三个这种类型的 bean。

  2. Spring 必须进行选择,因为你正在注入一个单个的 bean,但没有限定符,Spring 无法进一步缩小搜索范围。

    故事结束:出现错误。

注意: 如果你想要所有类型为 String 的 bean,你可以使用 @Autowire 注入一个 List<String>,然后自行决定哪一个适合你的需求。

英文:
  1. You are @Autowire'ing a String

    So, in your application context, there are three beans with that type.

  2. 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.

huangapple
  • 本文由 发表于 2023年6月6日 01:27:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76408739.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定