7.5.6 使用自动装配注入合作者Bean
Spring
能自动装配Bean
与Bean
之间的依赖关系,即无须使用ref
显式指定依赖Bean
,而是由Spring
容器检査XML
配置文件内容,根据某种规则,为调用者Bean
注入被依赖的Bean
。
Spring的自动装配
Spring
的自动装配
可通过<beans>
元素的default-autowire
属性指定,该属性对配置文件中所有的Bean
起作用;
也可通过<bean.>
元素的autowire
属性指定,该属性只对该Bean
起作用。
从上面介绍不难发现:在同一个Spring
容器中完全可以让某些Bean
使用自动装配,而另一些Bean
不使用自动装配。
自动装配可以减少配置文件的工作量,但降低了依赖关系的透明性和清晰性。
autowire属性值
autowire
、 default-autowire
属性可以接受如下值。
属性值 |
描述 |
no |
不使用自动装配。Bean 依赖必须通过ref 元素定义。这是默认的配置,在较大的部署环境中不鼓励改变这个配置,显式配置合作者能够得到更清晰的依赖关系。 |
byName |
根据setter 方法名进行自动装配。 Spring 容器查找容器中的全部Bean ,找出其id 与setter 方法名去掉set 前缀,并小写首字母后的同名的Bean 来完成注入。如果没有找到匹配的Bean 实例,则Spring 不会进行任何注入。 |
byType |
根据setter 方法的形参类型 来自动装配。 Spring 容器查找容器中的全部Bean ,如果正好有一个Bean 的类型与setter 方法的形参类型匹配 ,就自动注入这个Bean ;如果找到多个这样的Bean ,就抛出一个异常;如果没找到这样的Bean ,则什么都不会发生, setter 方法不会被调用。 |
constructor |
与byType 类似,区别是用于自动匹配构造器的参数。如果容器不能恰好找到一个与构造器参数类型匹配的Bean ,则会抛出一个异常。 |
autodetect |
Spring 容器根据Bean 内部结构,自行决定使用constructor 还是使用byType 策略。如果找到一个默认的构造函数,那么就会应用byType 策略。 |
由此可见, byName
策略是根据setter
方法的方法名与Bean
的id
进行匹配;byType
策略是根据setter
方法的参数类型
与Bean
的类型进行匹配。
7.5.6.1 byName规则
byName
规则是指setter
方法的方法名与Bean
的id
进行匹配,假如Bean A
的实现类包含setB()
方法,而Spring
的配置文件恰好包含id
为b
的Bean
,则Spring
容器会将b
实例注入Bean A
中。如果容器中没有名字匹配的Bean
,则Spring
不会做任何事情。
程序示例
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\byName └─src\ ├─beans.xml ├─lee\ │ └─SpringTest.java └─org\ └─crazyit\ └─app\ └─service\ ├─Dog.java ├─impl\ │ ├─Chinese.java │ └─GunDog.java └─Person.java
|
beans.xml
看如下配置文件。
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese" autowire="byName" /> <bean id="gunDog" class="org.crazyit.app.service.impl.GunDog"> <property name="name" value="wangwang" /> </bean> </beans>
|
Chinese.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package org.crazyit.app.service.impl;
import org.crazyit.app.service.*;
public class Chinese implements Person { private Dog dog; public void setGunDog(Dog dog) { this.dog = dog; } public Dog getDog() { return this.dog; } public void test() { System.out.println("我是一个普通人,养了一条狗:" + getDog().run()); } }
|
上面的配置文件指定了byName
自动装配策略,而且Chinese
类恰好有如下setter
方法:
1 2 3 4 5
| public void setGunDog(Dog dog) { this.dog = dog; }
|
上面setter
方法的方法名为setGunDog
, Spring
容器就会寻找容器中id
为gunDog
的Bean
,
- 如果能找到这样的
Bean
,该Bean
就会作为调用setGunDog()
方法的参数;
- 如果找不到这样的
Bean, Spring
就不调用setGunDog()
方法
7.5.6.2 byType规则
byType
规则是根据setter
法的参数类型与Bean
的类型进行匹配:
- 假如
A
实例有setB(B b)
方法,而Spring
的配置文件中恰好有一个类型为B
的Bean
实例,则容器为A
注入类型匹配的Bean
实例;
- 如果容器中没有类型为
B
的实例, 则Spring
不会调用setB()
方法;
- 但如果容器中包含多于一个的
B
实例,则程序将会抛出异常。
程序示例
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\byType\src ├─beans.xml ├─lee\ │ └─SpringTest.java └─org\ └─crazyit\ └─app\ └─service\ ├─Dog.java ├─impl\ │ ├─Chinese.java │ ├─GunDog.java │ └─PetDog.java └─Person.java
|
beans.xml
看如下配置文件。
1 2 3 4 5 6 7 8 9 10 11 12
| <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese" autowire="byType" /> <bean id="gunDog" class="org.crazyit.app.service.impl.GunDog"> <property name="name" value="wangwang" /> </bean> </beans>
|
上面的配置文件指定了byType
自动装配策略,而且Chinese
类恰好有如下setter
方法。
1 2 3 4 5
| public void setDog(Dog dog) { this.dog = dog; }
|
只有一个类型的Bean对象的情况
上面setter
法的形参类型是Dog
,而Spring
容器中的org.crazyit.app.service.impl.GunDog
类实现了Dog
接口,因此Spring
会以该Bean
为参数来调用chinese
的setDog
方法。
有两个同类型的Bean对象的情况
但如果在配置文件beans.xml
中再配置一个Bean
,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese" autowire="byType" /> <bean id="gunDog" class="org.crazyit.app.service.impl.GunDog"> <property name="name" value="wangwang" /> </bean> <bean id="petDog" class="org.crazyit.app.service.impl.PetDog"> <property name="name" value="ohoh" /> </bean> </beans>
|
此时, Spring
将无法按byType
策略进行自动装配,因为容器中有两个类型为Dog
的Bean
,Spring
无法确定应为chinese bean
注入哪个Bean
,所以程序将抛出异常.
同时指定自动装配和使用ref显示指定依赖时
当一个Bean
既使用自动装配依赖,又使用ref
显式指定依赖时,则使用ref
显式指定的依赖覆盖
自动装配依赖。在如下配置文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese" autowire="byType"> <property name="dog" ref="petDog" /> </bean> <bean id="gunDog" class="org.crazyit.app.service.impl.GunDog"> <property name="name" value="wangwang" /> </bean> <bean id="petDog" class="org.crazyit.app.service.impl.PetDog"> <property name="name" value="ohoh" /> </bean> </beans>
|
因为使用ref
显式指定的依赖关系将覆盖自动装配的依赖关系,所以自动转配失效,程序不会抛出异常.
对于大型的应用,不鼓励使用自动装配。虽然使用自动装配可减少配置文件的工作量,但大大降低了依赖关系的清晰性和透眀性。依赖关系的装配依赖于源文件的属性名或属性类型,导致Bean
与Bean
之间的耦合降低到代码层次,不利于高层次解耦
将某些Bean排除在自动装配之外
在某些情况下,程序希望将某些Bean
排除在自动装配之外,不作为Spring
自动装配策略的候选者此时可设置autowire-candidate
属性,通过为<bean>
元素设置autowire-candidate="false"
,即可将该Bean
排除在自动装配之外,容器在查找自动装配Bean
时将不考虑该Bean
:
除此之外,还可通过在<beans>
元素中指定defaul-autowire-candidates
属性将一批Bean
排除在自动装配之外。 default-autowire-candidates
属性的值允许使用模式字符串
,例如指定default-autowire-candidates="*abc"
,则所有以"abc"
结尾的Bean
都将被排除在自动装配之外。不仅如此,该属性甚至可以指定多个模式字符串,这样所有匹配任一模式字符串的Bean
都将被排除在自动装配之外。
例如,把上述配置文件改成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="chinese" class="org.crazyit.app.service.impl.Chinese" autowire="byType"> </bean> <bean id="gunDog" class="org.crazyit.app.service.impl.GunDog"> <property name="name" value="wangwang" /> </bean> <bean id="petDog" class="org.crazyit.app.service.impl.PetDog" autowire-candidate="false"> <property name="name" value="ohoh" /> </bean> </beans>
|
这样petDog
这个被排除在自动转配之外,则此时只有gunDog
符合byType
自动装配要求,程序依然可以正常运行.
剩下的两种自动装配策略与byName
、 byType
大同小异,此处不再赘述。
原文链接: 7.5.6 使用自动装配注入合作者Bean