关于Spring的自动装配问题
自动装配:Spring IoC 容器提供了对相互协作的Bean进行自动装配的功能。可以自动让Spring通过检查容器中的内容,来替开发人员指定Bean的依赖关系。由于autowire 可以针对单个Bean设置,因此可以让有些Bean使用autowire,有些Bean不使用。autowire的方便之处在于减少或消除对属性或构造器参数的设置,从而简化配置文件。autowire的五种类型:1
自动装配: Spring IoC 容器提供了对相互协作的Bean进行自动装配的功能。可以自动让Spring通过检查容器中的内容,来替开发人员指定Bean的依赖关系。由于autowire 可以针对单个Bean设置,因此可以让有些Bean使用autowire,有些Bean不使用。autowire的方便之处在于减少或消除对属性或构造器参数的设置,从而简化配置文件。
autowire的五种类型:
1、no :默认值,表明不使用自动装配。可以通过元素显示指定依赖,显示指定可以使配置更灵活、更清晰。
2、byName :根据属性名自动装配。此项将检查容器并查找id 值与属性名完全一致的Bean,将该Bean与属性自动装配。
byName示例:
Film类有如下属性:
public class Film {
private Lolo lo;
private Koko ko;
public Film() {
super();
// TODO Auto-generated constructor stub
}
----此后均省略setter,getter----
}
Koko类:
public class Koko {
private String name;
public Koko() {
super();
// TODO Auto-generated constructor stub
}
Lolo类:
public class Lolo {
private String name;
public Lolo() {
super();
// TODO Auto-generated constructor stub
}
}
配置文件(ApplicationContext.xml):
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="byName">
</bean>
</beans>
main方法测试:
public static void main(String[] args) {
ApplicationContext actx= new ClassPathXmlApplicationContext("ApplicationContext.xml");
System.out.println("-----------------");
Film film1= (Film) actx.getBean("film");
System.out.println(film1.getKo().getName());
System.out.println(film1.getLo().getName());
System.out.println("-----------------");
}
Console输出
:
修改配置文件:
<beans>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="byName">
</bean>
</beans>
再次运行Console结果
3、byType: 如果容器中存在一个与指定属性类型相同的Bean,那么将对该属性自动装配。如果存在多个该类型的Bean,那么将会抛出异常(NoUniqueDefinitionException),若没有找到相匹配的Bean,不会抛出异常,也不会对属性进行设置,此时可以通过设置dependency-check=”objects”让spring抛出异常。
byType示例:
Film类:
public class Film {
private Lolo lo;
private Koko ko;
public Film() {
super();
// TODO Auto-generated constructor stub
}
}
配置文件:
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="byType">
</bean>
</beans>
Console
存在多个与该属性类型相同的Bean时:
修改配置文件:容器中存在两个Lolo类型的Bean
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo1" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="lo2" class="com.pojo.Lolo">
<property name="name" value="怪怪"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="byType">
</bean>
</beans>
Console
不存在与该属性类型相同的Bean时:
修改配置文件:容器中不存在Lolo类型的Bean
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="byType">
</bean>
</beans>
console:
4、constructor: 与byType的方式类似,不同之处在于它应用于构造器的参数,根据构造器的参数类型进行自动装配。如果在容器中没有找到与构造器参数类型一致的Bean,那么将会抛出异常。
(1)Film构造器参数的数量与属性的数量相同
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
}
public Film() {
super();
// TODO Auto-generated constructor stub
}
}
配置文件:
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="constructor">
</bean>
</beans>
Spring根据Film构造器每个参数的类型,在容器中匹配,对film Bean进行装配
console:
(2)Film构造器参数的数量比属性的数量少
public class Film {
private Lolo lo;
private Koko ko;
//构造器中只有lo属性
public Film(Lolo lo) {
super();
this.lo = lo;
}
public Film() {
super();
}
}
配置文件:
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="constructor">
</bean>
</beans>
console:
构造器参数中没有ko属性,spring没有对这个属性进行装配
(3)只有默认的构造器时:
public class Film {
private Lolo lo;
private Koko ko;
public Film() {
super();
}
}
配置文件:
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="constructor">
</bean>
</beans>
console:
至于原因嘛,自己猜!
(4)一次蛋疼的纯属娱乐的测试
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo) {
super();
this.lo = lo;
}
public Film(Koko ko) {
super();
this.ko = ko;
}
public Film() {
super();
}
}
配置文件
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="constructor">
</bean>
</beans>
console:
film的lo属性没有装配,ko属性装配了
我们修改Film的那几个构造器的顺序
public class Film {
private Lolo lo;
private Koko ko;
//改变一下顺序
public Film(Koko ko) {
super();
this.ko = ko;
}
public Film(Lolo lo) {
super();
this.lo = lo;
}
public Film() {
super();
}
}
配置文件不变
再看结果
:
film的Ko属性没有被装配,lo属性装配了
后续的构造器中参数对应的属性被装配了,前面的没有被装配,是不是很有意思
(5)回到第(1)种情形,但容器中有多个相同类型的Bean
//注释掉默认的构造方法
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
}
/**
public Film() {
super();
}
*/
}
配置文件进行修改,容器中有多个Lolo类型的Bean
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo1" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="lo2" class="com.pojo.Lolo">
<property name="name" value="怪怪"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="constructor">
</bean>
</beans>
console
第二个异常:
继续测试,取消默认构造方法的注释
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
}
public Film() {
super();
// TODO Auto-generated constructor stub
}
配置文件不变
console:
个人理解为按照第一个构造方法的参数匹配行不通,就使用默认的构造方法进行constructor自动装配,两个属性就全变成了null(这只是个人的理解,还请大神指点迷津)
(6)容器中不存在构造器参数中某一类型的Bean时
//注释掉默认构造方法
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
}
/**
public Film() {
super();
}
*/
}
修改配置文件:删除Lolo类型的Bean
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="constructor">
</bean>
</beans>
Console:
第二个异常:
因为我们用的ApplicationContext接口,在初始化应用上下文时会实例化所有singleton Bean,而film设置了custructor自动装配,容器中缺少Lolo类型的bean ,也就报出了异常(4、constructor: 与byType的方式类似,不同之处在于它应用于构造器的参数,根据构造器的参数类型进行自动装配。如果在容器中没有找到与构造器参数类型一致的Bean,那么将会抛出异常。)
继续测试,取消Film类默认构造方法的注释
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
}
public Film() {
super();
// TODO Auto-generated constructor stub
}
}
配置文件不变
console:
没有抛出异常,两个属性值全为null,估计也是参照了默认的构造方法进行自动装配
5、autodetect: 通过Bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现类中有默认的构造器,那么将使用byType方式。
autodetect示例:
类中没有默认的构造器时
//注释默认的构造器
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
System.out.println("使用了constructor");
}
/**
public Film() {
super();
System.out.println("使用了byType");
}
*/
}
配置文件:
<beans>
<bean id="ko" class="com.pojo.Koko">
<property name="name" value="蛇蛇"/>
</bean>
<bean id="lo" class="com.pojo.Lolo">
<property name="name" value="皮皮"/>
</bean>
<bean id="film" class="com.pojo.Film" autowire="autodetect">
</bean>
</beans>
console:
类中存在默认构造器时
//取消默认构造器的注释
public class Film {
private Lolo lo;
private Koko ko;
public Film(Lolo lo, Koko ko) {
super();
this.lo = lo;
this.ko = ko;
System.out.println("使用了constructor");
}
public Film() {
super();
System.out.println("使用了byType");
// TODO Auto-generated constructor stub
}
}
配置文件不变
console:
结语:感谢您阅读,以上纯属个人学习理解,毕竟水平有限,如有错误,还请您指点迷津!
更多推荐
所有评论(0)