您的位置:首页 > 编程语言 > Java开发

关于Spring的自动装配问题

2016-11-27 13:48 323 查看
自动装配: 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.po
4000
jo.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:



结语:感谢您阅读,以上纯属个人学习理解,毕竟水平有限,如有错误,还请您指点迷津!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: