了解Spring自动装配
基于J2EE平台的框架纷繁复杂。而大多数框架中都有着复杂的配制文件,都需要程序员去研究去掌握(oh,该死的配置文件),Spring作为其中的佼佼者也不能免俗。但它却提供了一套能让程序员偷懒的小规则:自动装配。(感激得,终于了解我们Coder的心声了). Spring的IOC容器通过Java反射机制了解了容器中所存在Bean的配置信息,这包括构造函数方法的结构,属性的信息,而正是
基于J2EE平台的框架纷繁复杂。而大多数框架中都有着复杂的配制文件,都需要程序员去研究去掌握(oh,该死的配置文件),Spring作为其中的佼佼者也不能免俗。但它却提供了一套能让程序员偷懒的小规则:自动装配。(感激得,终于了解我们Coder的心声了).
Spring的IOC容器通过Java反射机制了解了容器中所存在Bean的配置信息,这包括构造函数方法的结构,属性的信息,而正是由于这个原因,Spring容器才能够通过某种规则来对Bean进行自动装配,而无须通过显式的方法来进行配制。
下面让我们来看看Spring为我们提供的自动装配有那些(通过指定元素的autowire="<自动装配类型>")
1,byName 根据属性名自动装配。此选项将检查容器并根据名字查找
与属性完全一致的bean,并将其与属性自动装配。
2,byType 如果容器中存在一个与指定属性类型相同的bean,那么将与
该属性自动装配;如果存在多个该类型bean,那么抛出异常,
并指出不能使用byType方式进行自动装配;如果没有找
到相匹配的bean,则什么事都不发生,也可以通过设置
dependency-check="objects"让Spring抛出异常。
3,constructor 与byType方式类似,不同之处在于它应用于构造器参数。
如果容器中没有找到与构造器参数类型一致的bean,
那么抛出异常。
4,autodetect 通过bean类的自省机制(introspection)来决定是
使用constructor还是byType方式进行自动装配。
如果发现默认的构造器,那么将使用byType方式,否则采用
constructor。
首先让我们来看看byName是怎么进行装配的。(假设有Boss类)
public class Boss(){
private String name;
private Car car;
省略get/Setter方法
}
在配置中我们采用byName的自动装配方式:
<bean id="car" class="com.test.auto.Car">
<property name="brand" value="aaa" />
<property name="price" value="1256" />
</bean>
<bean id="boss" class="com.test.auto.Boss" autowire="byName">
<property name="name" value="Tom" />
</bean>
如果未采用自动装配机制,在定义Bean的时候我们需要显式的通过property来进行配置,但通过autowire="byName"我们可以按命名自动装配,但如果通过名字进行装配的属性和目标Bean的属性类型不匹配,将回抛出ClassCastException。
当然我们同样可以采用byType的方式来进行Bean属性的装配,首先让我们来看看Spring神奇的byType的装配标准。它是以什么方式来衡量类型是否匹配的呢?(首先有A、B两个类)
如果A和B是相同类型:匹配!
A是B的子类:匹配!
A实现了B的接口:匹配!
所有的类都按类型匹配Object,所有的异常都按类型匹配于Exception;所有的List实现类都按类型匹配于List类。
那么Bean采用byType进行自动装配的时候,IOC容器中存在多个类型匹配的Bean应该怎么办呢?Spring当然是不会知道选择哪个作为匹配对象的,所以它会抛出Unsatisfied-DependecncyException。
Spring2.1中允许用户通过@Autowired注解来对Bean的属性变量、属性Setter方法以及构造函数进行标注,配合AutowiredAnnotationBeanPostProcessor(好长啊。。)完成对Bean的自动装配。下面来看看实际的例子:
public class Boss { private String title; @Autowired private Car car; public Boss() { this.title = title; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }
标注@Autowired注解的Bean并不会自动进行自动装配,它需要有一个配套的处理器,即AutowiredAnnotationBeanPostProcessor,该Bean后置处理器会在Spring容器启动时自动为标注为@Autowired注解的Bean实施自动装配。
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostP">
<bean id="boss" class="com.test.Boss"/>
<bean id="car"class="com.test.Car"/>
由于在Boss中的car属性被加上了@Autowired注解,那么它将被AutowiredAnnotationBeanPostProcess处理器自动装配到Boss Bean中去。
看了这么多自动装配,我们了解到存在多个匹配对象时候。Spring将会抛出异常,如果某个Bean不想被自动装配到其他的Bean中,Spring中的Bean有个autowire-candidate属性设置为false就可以达到我们的目的。
另外想说一下,一般要达到自动装配的目的我们都在Bean上autowire属性进行设置,如果我们想容器其他Bean都采用这种装配方式,那么就存在着所谓的全局自动装配策略了。Spring中的Beans元素标签的default-autowire属性就能满足我们的要求。默认是为no的不启用自动装配的。
谈了这么多自动装配的话题,自动装配已一两拨千金的方式完成了容器中Bean的装配工作,这种便捷的方式的确让人感到惬意啊。。但是象很多事物一样,这个功能也是一把双刃剑,减轻配置工作的同时,也造成了Bean之间的关系不明确,不清晰,也容易造成潜在的错误,比如说通过byName来装配,如果将属性名字改了后,Spring就不会将其自动装配给Bean的属性了,这个时候该属性值为null,而且Sping还不会抛出错误,因为通过属性注入的时候,属性值是可以选择的。而如果程序中有其他地方引用了该属性,将不可以避免的抛出NullPointerException异常,还有就是刚好有个重名的Bean那么可想而知,哈哈还真是危机不断啊,结果往往超出我么的预计啊。
更多推荐
所有评论(0)