Spring Autowired的一个小问题

最近学习Spring框架:在我自己写代码的过程中,发现,如果@Autowired注解用在属性上的话,最好要将该属性setter的方法去掉,起初的原因是我想测试一下当有两个Bean的类型(Type)一致是,需要让@Autowired配合使用@Qualifier才能找到唯一的bean。首先看一下我的xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

<bean id="cat222" class="com.luo.pojo.Cat">
<property name="catName" value="hao"/>
</bean>

<bean id="dog111" class="com.luo.pojo.Dog">
<property name="dogName" value="yue1"/>
</bean>

<bean id="dog" class="com.luo.pojo.Dog"> <!-- 重点看这里,有两个Dog类型的bean -->
<property name="dogName" value="yue"/>
</bean>


<bean id="people" class="com.luo.pojo.People" autowire="byType">
<property name="name" value="luo"/>
</bean>

<context:annotation-config/>

</beans>

然后我利用@Autowired 配合 @Qualifier 对dog进行自动装配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.luo.pojo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

public class People {
public String name;

@Autowired
private Cat cat;

@Autowired
@Qualifier("dog111") //根据我的设想,这里@Qualifier("dog111"),可以找到唯一的Bean
private Dog dog;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Cat getCat() {
return cat;
}

public void setCat(Cat cat) {
this.cat = cat;
}

public Dog getDog() {
return dog;
}

public void setDog(Dog dog) { //注意这里的set方法
this.dog = dog;
}

@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", cat=" + cat.toString() +
", dog=" + dog.toString() +
'}';
}
}

然后我测试了一下可以不可以实现自动装配,结果报错了:

Unsatisfied dependency expressed through bean property ‘dog’: No qualifying bean of type [com.luo.pojo.Dog] is defined: expected single matching bean but found 2: dog111,dog;

报错信息大概就是说无法找到唯一匹配的bean,找到了两个匹配的bean, 分别dog111和dog,诶奇了怪了我不是用@Qualifier(“dog111”)指明了当有多个类型匹配时,取id=“dog111"的那一个bean吗?怎么还会有冲突?

Debug无果后,想到@Autowired有两种使用方式,一种是直接使用在属性上,一种是使用在set方法上,于是将@Autowired和@Qualifier(“dog111”)使用在set方法上后,成功解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package com.luo.pojo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("dok111")
public class People {
public String name;

@Autowired
private Cat cat;

private Dog dog;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Cat getCat() {
return cat;
}

public void setCat(Cat cat) {
this.cat = cat;
}

public Dog getDog() {
return dog;
}

@Autowired //改到set方法上
@Qualifier("dog111")
public void setDog(Dog dog) {
this.dog = dog;
}

@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", cat=" + cat.toString() +
", dog=" + dog.toString() +
'}';
}
}

为什么会这样呢?在网上搜集了一下信息

  • 当注解写在成员变量(属性)上 就是spring通过读取xml配置返回一个bean
  • 当注解写在set方法上,就是spring通过读取xml配置返回一个bean,然后再用这个bean里面的属性,注入到成员变量当中。

那如果我同时写在属性和set方法上,会通过哪种方式呢?于是我进行了一下测试,将属性和set方法前都写上@Autowired和@Qualifier(“dog111”),代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.luo.pojo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("dok111")
public class People {
public String name;

@Autowired
private Cat cat;

@Autowired
@Qualifier("dog111")
private Dog dog;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Cat getCat() {
return cat;
}

public void setCat(Cat cat) {
this.cat = cat;
}

public Dog getDog() {
return dog;
}

@Autowired
@Qualifier("dog111")
public void setDog(Dog dog) {
System.out.println("调用了set方法");
this.dog = dog;
}

@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", cat=" + cat.toString() +
", dog=" + dog.toString() +
'}';
}
}

最后屏幕输出了调用了set方法,好像说明了当同时存在的时候,还是默认使用了set方法,先获取bean,再进行配置,这也解释了为什么我们最刚开始只在属性上写@Autowired和@Qualifier(“dog111”)会报错了,因为此时spring还是会通过set方法进行注入,而此时set方法发现两个类型相同,无法唯一匹配就报错了

所以解决的方式有两个:

  • 删除掉set方法,使用加在属性上的注解属性直接配置
  • 给set方法前也加上注解
文章作者: luo
文章链接: https://luo41.top/2021/09/18/Spring-Autowired的一个小问题/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 luo's Blog