问题思考
没有自动装配的时候是怎么注入依赖的?
假设用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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class Person {
private Superpower superpower;
public Superpower getSuperpower() { return superpower; }
public void setSuperpower(Superpower superpower) { this.superpower = superpower; } }
public class Superpower {
private String name;
private String description;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; } }
<!--配置Bean--> <bean id="person" class="com.hph.model.Person"> <!--配置JavaBean的属性--> <property name="superpower" ref="superpower"/> </bean>
<bean id="superpower" class="com.hph.model.Superpower"> <property name="name" value="闪电侠"/> <property name="description" value="超能力"/> </bean>
|
Person通过Setter方式使用ref属性注入Superpower类型的依赖项bean
执行结果:
1 2 3 4 5 6 7 8 9 10
| public static void main(String[] args) {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("test-config.xml");
Person person = (Person)classPathXmlApplicationContext.getBean("person");
System.out.println(person.getSuperpower().getName()+"------"+person.getSuperpower().getDescription()); }
|
打印输出:

使用自动装配
改xml配置即可(以byName为例)
1 2 3 4 5 6 7
| <bean id="person" class="com.hph.model.Person" autowire="byName" />
<bean id="superpower" class="com.hph.model.Superpower"> <property name="name" value="闪电侠"/> <property name="description" value="超能力"/> </bean>
|
打印输出:

可以发现,当使用自动装配的方式后,只需要加autowire属性即可将依赖项注入进来,不需要写property属性进行显示配置需要注入哪些依赖项;
那么,可以知道,自动装配是为了解决依赖配置复杂的问题
autowire不同类型之间的区别
官方给出四种自动装配模式,分别为no、byName、byType和constructor,下面看看byName、byType和constructor这三种模式的区别
byName
当bean查找并且注入依赖项时,通过依赖项变量名进行匹配,并且是基于Setter注入
代码如下:
当bean person注入名称为superpowerA的依赖项时,通过与id或name进行查找匹配的bean进行注入
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
| public class Person {
private Superpower superpowerA;
public Superpower getSuperpowerA() { return superpowerA; }
public void setSuperpowerA(Superpower superpowerA) { this.superpowerA = superpowerA; } }
public interface Superpower {
void release(); }
public class SuperpowerA implements Superpower {
public void release() {
System.out.println("释放超能力SuperpowerA:"); } }
public class SuperpowerB implements Superpower {
public void release() {
System.out.println("释放超能力SuperpowerB"); } }
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byName"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输入:

为了验证是否是通过id或name进行匹配的,改下代码
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
| public class Person {
private Superpower superpowerB;
public Superpower getSuperpowerB() { return superpowerB; }
public void setSuperpowerB(Superpower superpowerB) { this.superpowerB = superpowerB; } }
部分代码省略…………
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byName"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输出:

证明通过id进行匹配
验证是否通过name进行匹配
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
| public class Person {
private Superpower superpowerB;
public Superpower getSuperpowerB() { return superpowerB; }
public void setSuperpowerB(Superpower superpowerB) { this.superpowerB = superpowerB; } }
部分代码省略…………
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byName"/>
<bean id="superpowerA" name="superpowerB" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerBB" name="a" class="com.hph.model.SuperpowerB"/>
|
打印输出:

确实匹配了name
疑问:如果id和name存在相同会怎样?
改代码:
1 2 3 4 5 6 7 8 9
| 部分代码省略…………
<bean id="person" class="com.hph.model.Person" autowire="byName"/>
// name值和下面那个bean的id相同 <bean id="superpowerA" name="superpowerB" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" name="a" class="com.hph.model.SuperpowerB"/>
|
打印输出:直接抛异常,提示superpowerB已被使用

验证:是否是基于Setter进行注入
代码如下:
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
| public class Person {
private Superpower superpowerA;
public Superpower getSuperpowerA() { return superpowerA; }
public void setSuperpowerA(Superpower superpowerA) { System.out.println("通过Setter方式进行注入"); this.superpowerA = superpowerA; } }
public interface Superpower {
void release(); }
部分代码省略…………
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byName"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输出:

再加一个构造函数,验证是否会通过构造函数进行注入
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
| public class Person {
private Superpower superpowerA; public Person(Superpower superpowerA) { this.superpowerA = superpowerA; }
public Superpower getSuperpowerA() { return superpowerA; }
public void setSuperpowerA(Superpower superpowerA) { System.out.println("通过Setter方式进行注入"); this.superpowerA = superpowerA; } }
public interface Superpower {
void release(); }
部分代码省略…………
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byName"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输出:抛异常,提示在创建bean person的时候没有找到默认构造函数

byType
当bean查找并且注入依赖项时,通过依赖项类型进行匹配,并且是基于Setter注入
代码如下
bean person注入类型为Superpower的bean,但是该类型有两个实现类SuperpowerA和SuperpowerB,通过类型查找时不知道注入哪一个,所以会抛异常
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
| public class Person {
private Superpower superpower;
public Superpower getSuperpower() { return superpower; }
public void setSuperpower(Superpower superpower) {
this.superpower = superpower; } }
public interface Superpower {
void release(); }
public class SuperpowerA implements Superpower {
public void release() {
System.out.println("释放超能力SuperpowerA:"); } }
public class SuperpowerB implements Superpower {
public void release() {
System.out.println("释放超能力SuperpowerB"); } }
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byType"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输出:提示找到两个匹配的bean

当减少为一个时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Person {
private Superpower superpower;
public Superpower getSuperpower() { return superpower; }
public void setSuperpower(Superpower superpower) {
this.superpower = superpower; } }
部分代码省略…………
<!--配置Bean--> <bean id="person" class="com.hph.model.Person" autowire="byType"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
|
打印输出:正常

那如果有多个实现类,并且能正常注入呢
可以通过primary属性指定首选的注入bean
1 2 3 4 5 6 7 8 9
| 部分代码省略…………
<bean id="person" class="com.hph.model.Person" autowire="byType"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
// 指定该bean为首选注入 <bean id="superpowerB" class="com.hph.model.SuperpowerB" primary="true"/>
|
打印输出:

constructor
这种方式和byType类似,不同的是constructor是基于构造函数注入的,也就是说依赖项注入的时机不一样,byType是实例化之后通过setter方法注入,而constructor是在实例化的时候就开始注入
代码如下:
Person中没有定义带参数的构造函数,默认无参构造函数
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
| public class Person {
private Superpower superpower;
public Superpower getSuperpower() { return superpower; }
public void setSuperpower(Superpower superpower) {
this.superpower = superpower; } }
public interface Superpower {
void release(); }
public class SuperpowerA implements Superpower {
public void release() {
System.out.println("释放超能力SuperpowerA:"); } }
public class SuperpowerB implements Superpower {
public void release() {
System.out.println("释放超能力SuperpowerB"); } }
<!--配置Bean-->
<bean id="person" class="com.hph.model.Person" autowire="constructor"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输出:提示空指针,依赖没有注入进来,因为没有定义带Superpower类型参数的构造函数,通过默认无参构造函数实例化,没有注入Superpower依赖项
Person中有定义setter方法,也恰好说明了constructor类型不是通过setter进行注入的

定义带Superpower类型参数的构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Person {
private Superpower superpower;
public Person(Superpower superpower) { this.superpower = superpower; }
public Superpower getSuperpower() { return superpower; }
public void setSuperpower(Superpower superpower) {
this.superpower = superpower; } }
部分代码省略…………
|
打印输出:空指针没有了,提示存在相同类型的多个bean

和byType一样,通过primary属性指定首选依赖项
1 2 3 4 5 6 7 8
| 部分代码省略…………
<bean id="person" class="com.hph.model.Person" autowire="constructor"/>
<bean id="superpowerA" class="com.hph.model.SuperpowerA" primary="true"/>
<bean id="superpowerB" class="com.hph.model.SuperpowerB"/>
|
打印输出:
