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