Spring能自动装配Bean与Bean之间的依赖关系,即无须使用 ref 显式指定依赖Bean。由BeanFactory检查XML配置文件内容,根据某种规则,为主调Bean注入依赖关系。
Spring的自动装配可通过<beans.../>元素的 default-autowire 属性指定,也可通过<bean.../>元素的 autowire 属性指定。自动装配可以指定到单独Bean,也就是说,同一个容器中完全可让某些Bean使用自动装配,而另一些Bean不使用。
自动装配可以减少配置文件的工作量,但降低了依赖关系的透明性和清晰性。
使用autowire 属性配置自动装配,autowire 属性可以接受如下值:
> no :不使用自动配置。Bean依赖关系必须通过 ref 元素定义。只是默认的配置,在较大的部署环境中不鼓励改变这个配置,显式配置合作者能够得到更清晰的依赖关系。
> byName:根据属性名自动装配。BeanFactory查找容器中的全部Bean,找出其中id属性与属性同名的Bean来完成注入。如果没有找到匹配的Bean实例,则Spring不会进行任何注入。
> byType:根据属性类型自动装配。BeanFactory查找容器中的全部Bean,如果正好有一个与依赖属性类型相同的Bean,就自动注入这个属性;如果有多个这样的Bean,就抛出一个异常;如果没有匹配的Bean实例,则什么都不会发生,属性不会被设置。如果需要无法自动装配时抛出异常,则设置dependency-check="objects"。
> constructor:与byType类似,区别是用于构造注入的参数。如果BeanFactory中不是恰好有一个Bean与构造参数类型相同,则会抛出一个异常。
> autodetect:BeanFactory根据Bean内部结构,决定使用constructor或byType。如果找到一个默认的构造函数,那么就会应用byType。
byType规则:通过名字注入依赖关系,假如Bean A9的实现类包括setB()方法,而Spring的配置文件恰好包含id 为b的Bean,则Spring容器会将b实例注入Bean A中。如果容器中没有名字匹配的Bean,Spring则不会做任何事情。
package autowire;
public class Man {
private Dog dog;
public void setGundog(Dog dog){ //byName需要提供的依赖注入的方法,set+Bean名(Bean名首字母大写)
this.dog = dog;
}
public void auto(){
System.out.println(dog.d());
}
}
或者
package autowire;
public interface M {
public void auto();
}
+
package autowire;
public class Man implements M {
//使用自动装配注入合作者Bean
private Dog dog;
public void setGundog(Dog dog){ //byName需要提供的依赖注入的方法,set+Bean名(Bean名首字母大写)
this.dog = dog;
}
public void auto(){
System.out.println(dog.d());
}
}
package autowire;
public interface Dog {
public String d();
}
package autowire;
public class Gundog implements Dog {
private String name;
public void setName(String name) {
this.name = name;
}
public String d() {
// TODO Auto-generated method stub
return name;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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-4.2.xsd"
>
<!-- 自动装配 byName没找到匹配的Bean实例不会有注入,byType同样,但有多个这样属性类型的Bean时会抛出异常 -->
<bean id="man" class="autowire.Man" autowire="byName"/>
<bean id="gundog" class="autowire.Gundog">
<property name="name" value="wangwang"/>
</bean>
</beans>
package autowire;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("bean.xml");
Man m = ctx.getBean("man",Man.class);
//M m = ctx.getBean("man",M.class);
m.auto();
}
}
byType规则:根据类型匹配来注入依赖关系。假如A实例有setB(B b)方法,而Spring配置文件中恰好有一个类型B的Bean实例,容器为A注入类型匹配的Bean实例;如果容器中没有一个类型为B的实例,则什么都不会发生;但如果容器中有多余一个的B实例,都将会抛出异常。
package autowire;
public class Man implements M { //可以不使用接口
private Dog dog;
/*public void setGundog(Dog dog){
this.dog = dog;
}*/
public void setDog(Dog dog) { //byType需要setter方法的参数类型与容器中Bean的类型相同,
this.dog = dog; //在这里setGundog(Dog dog)、setDog(Dog dog)都可完成依赖注入
}
public void auto(){
System.out.println(dog.d());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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-4.2.xsd"
>
<!-- 自动装配 byName没找到匹配的Bean实例不会有注入,byType同样,但有多个这样属性类型的Bean时会抛出异常 -->
<bean id="man" class="autowire.Man" autowire="byType"/>
<bean id="gundog" class="autowire.Gundog">
<property name="name" value="wangwang"/>
</bean>
</beans>
测试及结果都一样
异常情况:
<?xml version="1.0" encoding="UTF-8"?>
<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-4.2.xsd"
>
<!-- 自动装配 byName没找到匹配的Bean实例不会有注入,byType同样,但有多个这样属性类型的Bean时会抛出异常 -->
<bean id="man" class="autowire.Man" autowire="byType"/>
<bean id="gundog" class="autowire.Gundog">
<property name="name" value="wangwang"/>
</bean>
<!-- 多于一个同为Dog类型的Bean -->
<bean id="petdog" class="autowire.Petdog">
<property name="name" value="ohoh"/>
</bean>
</beans>
package autowire;
public class Petdog implements Dog {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String d() {
// TODO Auto-generated method stub
return name;
}
}
即用自动装配依赖,又使用ref显式指定依赖时:
<?xml version="1.0" encoding="UTF-8"?>
<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-4.2.xsd"
>
<!-- 即用自动装配依赖,又使用ref显式指定依赖时 -->
<bean id="man" class="autowire.Man" autowire="byName">
<property name="gundog" ref="petdog"/>
</bean>
<bean id="gundog" class="autowire.Gundog">
<property name="name" value="wangwang"/>
</bean>
<!-- 多于一个同为Dog类型的Bean -->
<bean id="petdog" class="autowire.Petdog">
<property name="name" value="ohoh"/>
</bean>
</beans>
结果
显式指定的依赖覆盖自动装配