1. 什么是自动装配
自动装配是相对于手动装配而言的
手动装配:以value或ref的方式明确指定属性值都是手动装配
自动装配:根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中
自动装配有注解和XML配置两种实现方式。在XML文档中进行的自动装配略显笨拙,在项目中更多的使用注解的方式实现
2. autowire属性值
2.1. autowire=no/default
autowire=no 就是不启用自动装配
autowire=default 是默认值。由上级beans标签的default-autowire属性确定。默认效果和autowire=no一样,不启用自动装配
2.2. autowire=byName
1 |
|
1 |
|
1 | <bean id="car" class="bean.Car"> |
运行测试,看到car自动装配了1
2
3
4
5
6
public void test() throws Exception {
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = ioc.getBean(Person.class);
System.out.println(person);
}
现在探索一下原理。修改一下Person类,只有一个setCar方法。运行测试方法,发现setCar()被调用了1
2
3
4
5public class Person {
public void setCar(Car haha) {
System.out.println("自动装配调用" + haha);
}
}
再修改,setCar方法名不变,参数类型改为其它类型,如String。再次运行,发现setCar()没有被调用1
2
3
4
5public class Person {
public void setCar(String haha) {
System.out.println("自动装配调用" + haha);
}
}
综上可知,自动装配的过程是:
- 找到setCar(),就认为Person有一个car属性
- Spring会去容器中查找id/name为car的组件,如果组件类型和setCar()参数的类型对应,则调用setCar(car),实现自动装配
2.3. autowire=byType
Bean配置1
<bean id="person" class="bean.Person" autowire="byType" />
编写Person,运行之前的测试方法,发现自动装配成功1
2
3
4
public class Person {
private Car car;
}
修改Person,修改一下属性名,只要与组件中的Car的id不相同即可。运行之前的测试方法,发现自动装配还是能成功1
2
3
4
public class Person {
private Car aaa;
}
探索一下原理。修改Person类,随便写一个setter方法,但是参数类型是Car。再运行测试方法,发现还是能自动装配
1 | public class Person { |
再修改,将参数修改为其它类型。运行测试方法,发现无法自动装配1
2
3
4
5public class Person {
public void setAbc(String haha) {
System.out.println("自动装配调用" + haha);
}
}
综上可知,byType自动装配取决于setter的参数类型,如果该参数类型与容器中某个组件的类型对应,就会调用setter,并将组件作为参数传入,实现自动装配
再想一下,如果有多个setter的参数类型都是Car,会发生什么事情呢?修改一下Person,两个setter的参数类型都是Car。运行之前的测试方法,发现两个setter都被调用了。也就是説,只要setter的参数类型与组件对应,所有的setter都会被调用1
2
3
4
5
6
7
8public class Person {
public void setAaa(Car aaa) {
System.out.println("自动装配调用aaa " + aaa);
}
public void setBbb(Car bbb) {
System.out.println("自动装配调用bbb " + bbb);
}
}
再想一下,如果容器中有多个Car组件,会自动装配哪个组件呢?修改Bean配置,注册2个Car组件1
2
3
4
5
6
7
8
9<bean id="car1" class="bean.Car">
<property name="name" value="car1" />
<property name="price" value="100.0" />
</bean>
<bean id="car2" class="bean.Car">
<property name="name" value="car2" />
<property name="price" value="200.0" />
</bean>
<bean id="person" class="bean.Person" autowire="byType"/>
再运行,抛出异常。这说明,如果容器中有多个Car组件,此时不应该通过byType将Car自动装配到Person中1
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'bean.Car' available: expected single matching bean but found 2: car1,car2
2.4. autowire=constructor
1 | public class Person { |
1 | <bean id="car1" class="bean.Car"> |
运行之前的测试方法,发现自动装配成功。说明只要Person有一个有参构造方法,其参数类型是Car,该类型与容器中组件的类型对应,就会调用该构造方法
如果容器中没有对应的组件,会怎样呢?修改Bean配置,只留一下Person组件1
<bean id="person" class="bean.Person" autowire="constructor" />
再运行,发现无参构造方法被调用。说明没有组件匹配时,Spring会调用无参构造对Bean进行实例化,不会抛什么异常
如果容器中有多个Car组件,会出现什么情况呢?尝试修改Bean配置文件,定义多个Car组件1
2
3
4
5
6
7
8
9<bean id="car1" class="bean.Car">
<property name="name" value="car1" />
<property name="price" value="100.0" />
</bean>
<bean id="car2" class="bean.Car">
<property name="name" value="car2" />
<property name="price" value="200.0" />
</bean>
<bean id="person" class="bean.Person" autowire="constructor" />
再运行测试方法,发现无参构造被调用了。也就是説,两个Car都没有匹配,自动装配没有成功。
修改一个有参构造方法的参数名,再运行,发现car1成功自动装配1
2
3
4
5
6
7
8
9public class Person {
public Person() {
System.out.println("无参构造");
}
/** 修改参数名,使参数名与容器中某个Car组件的id/name相对应 */
public Person(Car car1) {
System.out.println("自动装配car: " + car1);
}
}
经过以上实验,可总结如下:
- 容器中只有1个Car组件,只要Person的有参构造参数类型是Car,就能自动装配
- 容器中有多个Car组件,Person的有参构造参数类型不仅得是Car类型,参数名还要与其中一个组件的id/name相对应
- 如果无法自动装配,则调用无参构造对Person进行实例化。即能装就装,不装还能实例化,反正就是不报错。但是如果你没有给Person定义无参构造,在无法自动装配情况下,还是会报错的