1.Bean容器

<wbr></wbr>

1.1<wbr> BeanFactory</wbr>和 ApplicationContext

在Spring中,两个最基本最重要的包是 org.springframework.beans和org.springframework.context. 这两个包中的代码为Spring的反向控制 特性(也叫作依赖注射)提供了基础。 BeanFactory提供了一种先进的配置机制来管理任何种类bean(对象)。ApplicationContext建立在BeanFactory之上,并增加了其他的功能,比如更容易同SpringAOP特性整合, 消息资源处理(用于国际化),事件传递,以声明的方式创建ApplicationContext,可选的父上下文和与应用层相关的上下文(比如WebApplicationContext),以及其他方面的增强。

简而言之,BeanFactory提供了配置框架和基本的功能,而ApplicationContext为它增加了更强的功能,这些功能中的一些或许更加接近J2EE并且围绕企业级应用。一般来说,ApplicationContext是BeanFactory的完全超集, 任何BeanFactory功能和行为的描述也同样被认为适用于ApplicationContext

BeanFactory实际上是实例化,配置和管理众多bean的容器。 这些bean通常会彼此合作,因而它们之间会产生依赖。 BeanFactory使用的配置数据可以反映这些依赖关系中(一些依赖可能不像配置数据一样可见,而是在运行期作为bean之间程序交互的函数)。

一个BeanFactory可以用接口org.springframework.beans.factory.BeanFactory表示,这个接口有多个实现。 最常使用的简单的BeanFactory实现是org.springframework.beans.factory.xml.XmlBeanFactory。

很多情况下,用户代码不需要实例化BeanFactory,因为Spring框架代码会做这件事。例如,web层提供支持代码,在J2EEweb应用启动过程中自动载入一个SpringApplicationContext。在web.xml中通过配置:org.framework.web.context.ContextLoaderListener(对于实现了Servlet2.3的Web容器,两者皆可)或者org.framework.web.context.ContextLoaderServlet(对于实现了Servlet2.2的Web容器,只能用这个)。

不管是BeanFactory还是ApplicationContext,都是既可以通过声明的方式,也可以通过编程的方式实例化。

<wbr></wbr>

一个最基本的BeanFactory配置由一个或多个它所管理的Bean定义组成。在一个XmlBeanFactory中,根节点beans中包含一个或多个bean元素。



<beans>
<wbr> <bean id="..."  lang="EN-US" style="font-size:9pt"><span style="font-family:宋体"><wbr><wbr><wbr> ...</wbr></wbr></wbr></span></wbr>
<wbr> </bean></wbr>
<wbr> <bean id="..."  lang="EN-US" style="font-size:9pt"><span style="font-family:宋体"><wbr><wbr><wbr> ...</wbr></wbr></wbr></span></wbr>
<wbr> </bean></wbr>
</beans>



1.2 BeanDefinitions(Bean定义)

一个XmlBeanFactory中的Bean定义包括的内容有:

·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>classname:这通常是bean的真正的实现类。但是如果一个bean使用一个静态工厂方法所创建而不是被普通的构造函数创建,那么这实际上就是工厂类的classname

·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>bean行为配置元素:它声明这个bean在容器的行为方式(比如prototype或singleton,自动装配模式,依赖检查模式,初始化和析构方法)

·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>构造函数的参数和新创建bean需要的属性:举一个例子,一个管理连接池的bean使用的连接数目(即可以指定为一个属性,也可以作为一个构造函数参数),或者池的大小限制

·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>和这个bean工作相关的其他bean:比如它的合作者(同样可以作为属性或者构造函数的参数)。这个也被叫做依赖。

通过构造函数创建bean



<bean id="exampleBean"
<wbr><wbr><wbr><wbr><wbr>  lang="EN-US" style="font-size:9pt"><span style="font-family:宋体"><bean name="anotherExample"</span></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr>



<wbr></wbr>

通过静态工厂方法创建Bean



<bean id="exampleBean"
<wbr><wbr><wbr><wbr><wbr>  style="background:#f4f4f4;text-indent:18pt"><span lang="EN-US" style="font-size:9pt"><span style="font-family:宋体">factory-method="createInstance"/></span></span></wbr></wbr></wbr></wbr></wbr>



通过实例工厂方法创建bean



<bean id="myFactoryBean"
<wbr><wbr><wbr><wbr><wbr>  lang="EN-US" style="font-size:9pt"><span style="font-family:宋体"><wbr> ...</wbr></span></wbr></wbr></wbr></wbr></wbr>
</bean>
<!-- The bean to be created via the factory bean -->
<bean id="exampleBean"
<wbr><wbr><wbr><wbr><wbr> factory-bean="myFactoryBean"</wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr> factory-method="createInstance"/></wbr></wbr></wbr></wbr></wbr>



<wbr></wbr>

1.3 设置bean的属性和合作者

反向控制通常与依赖注入同时提及。基本的规则是bean通过以下方式来定义它们的依赖(比如它们与之合作的其他对象):构造函数的参数,工厂方法的参数;当对象实例被构造出来或从一个工厂方法返回后设置在这个实例上的属性。容器的工作就是创建完bean之后,真正地注入这些依赖。这完全是和一般控制方式相反的(因此称为反向控制)。

很显然通过使用它:代码变得非常清晰;当bean不再自己查找他们依赖的类而是由容器提供,甚至不需要知道这些类在哪里以及它们实际上是什么类型,这时高层次的解耦也变得很容易了。

反向控制/依赖注射存在两种主要的形式:

·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>基于setter的依赖注射,是在调用无参的构造函数或无参的静态工厂方法实例化你的bean之后,通过调用你的bean上的setter方法实现的。Spring一般提倡使用基于setter方法的依赖注射,因为很多的构造函数参数将会是笨重的,尤其在有些属性是可选的情况下。

·<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>基于构造函数的依赖注射,它是通过调用带有许多参数的构造方法实现的,每个参数表示一个合作者或者属性。 另外,调用带有特定参数的静态工厂方法来构造bean可以被认为差不多等同的, 接下来的文字会把构造函数的参数看成和静态工厂方法的参数类似。虽然Spring一般提倡在大多数情况下使用基于setter的依赖注射, 但是Spring还是完全支持基于构造函数的依赖注射,因为你可能想要在那些只提供多参数构造函数并且没有setter方法的遗留的bean上使用Spring。另外对于一些比较简单的bean,一些人更喜欢使用构造函数方法以确保bean不会处于错误的状态。

depends-on 元素可以用来在初始化使用这个元素的bean之前,强制一个或多个beans初始化。

拥有这些属性的bean依赖于被自己引用的bean,被引用的bean将会在属性设置前,必要的时候需要时初始化(如果是一个singletonbean可能已经被容器初始化)。所有的引用根本上是一个指向其他对象的引用,不过有3种形式指定被引用对象的id/name,这3种不同形式决定作用域和如何处理验证。

用ref元素的bean属性指定目标bean是最常见的形式,它允许指向的bean可以在同一个BeanFactory/ApplicationContext(无论是否在同一个XML文件中)中,也可以在父BeanFactory/ApplicationContext中。bean属性的值可以同目标bean的id属性相同,也可以同目标bean的name属性中任何一个值相同。



<wbr><wbr></wbr></wbr><wbr><ref bean="someBean"/></wbr>



用local属性指定目标bean可以利用XML解析器的能力在同一个文件中验证XMLid引用。local属性的值必须与目标bean的id属性一致。如果在同一个文件中没有匹配的元素,XML解析器将会产生一个错误。因此,如果目标bean在同一个XML文件中,那么使用local形式将是最好的选择(为了能够尽可能早的发现错误)。



<wbr></wbr><wbr><wbr> <ref local="someBean"/></wbr></wbr>



用parent属性指定目标bean允许引用当前BeanFactory(ApplicationContext)的父BeanFactory(ApplicationContext)中的bean。parent属性的值可以同目标bean的id属性相同,也可以同目标bean的name属性中的一个值相同,而且目标bean必须在当前BeanFactory(ApplicationContext)的父BeanFactory(ApplicationContext)中。当需要用某种proxy包装一个父上下文中存在的bean(可能和父上下文中的有同样的name),所以需要原始的对象用来包装它。



<ref parent="someBean"/><wbr></wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>



依赖属性的装配模式

注意:显式的指定依赖,比如property和constructor-arg元素,总会覆盖自动装配。自动装配的行为可以和依赖检查结合使用,依赖检查会在自动装配完成后发生。

1.4 <wbr></wbr>子bean定义(Bean继承)

一个子bean定义是一个能够从父bean定义继承配置数据的bean定义。它可以覆盖一些值,或者添加一些其他需要的值。使用父和子的bean定义可以节省很多的输入工作。实际上,这就是一种模版形式。

在一个XmlBeanFactory的bean定义中,使用parent属性指出一个子bean定义,而父bean则作为这个属性的值。



<bean id="inheritedTestBean"  lang="EN-US" style="font-size:9pt"><wbr><wbr><wbr> <property name="name"><value>parent</value></property></wbr></wbr></wbr>
<wbr><wbr><wbr> <property name="age"><value>1</value></property></wbr></wbr></wbr>
</bean>
<wbr></wbr>
<bean id="inheritsWithDifferentCla<wbr>ss"  lang="EN-US" style="font-size:9pt"><span style="font-family:宋体"><wbr><wbr><wbr><wbr><wbr> parent="inheritedTestBean" init-method="initialize"></wbr></wbr></wbr></wbr></wbr></span></wbr>
<wbr><wbr><wbr> <property name="name"><value>override</value></property></wbr></wbr></wbr>
<wbr><wbr><wbr> <!-- age should inherit value of 1 from parent --></wbr></wbr></wbr>
<wbr> </bean></wbr>



如果子bean定义没有指定class属性,将使用父定义的class属性,当然也可以覆盖它。 在后面一种情况中,子bean的class属性值必须同父bean的兼容,也就是它必须能够接受父亲的属性值。

一个子bean定义可以从父亲处继承构造函数参数,属性值以及方法,并且可以选择增加新的值。如果init-method,destroy-method和/或静态factory-method被指定了,它们就会覆盖父亲相应的设置。

剩余的设置将总是 从子定义处得到:依赖,自动装配模式,依赖检查,singleton,延迟初始化。

abstract="true"属性可以将一个Bean(一般是父Bean)定义为抽象的,这样它可以不被实例化,仅仅做为一个抽象类及模版。

<wbr></wbr>

1.5BeanFactoryAware

容器中多数的bean是singleton的。当一个singleton的bean需要同另一个singleton的bean合作(使用)时,或者一个非singleton的bean需要同另一个非singleton的bean合作的时候,通过定义一个bean为另一个bean的属性来处理这种依赖的关系就足够了。然而当bean的生命周期不同的时候就有一个问题。想想一下一个singleton bean A,或许在每次方法调用的时候都需要使用一个non-singleton bean B。容器仅仅会创建这个singleton beanA一次,因此仅仅有一次的机会去设置它的属性。因此容器没有机会每次去为beanA提供新的beanB的实例。一个解决这个问题的方法是放弃一些反向控制。BeanA可以通过实现 BeanFactoryAware知道容器的存在,使用编程的手段,在需要的时候通过调用getBean("B")来向容器请求新的beanB实例。对于实现了org.springframework.beans.factory.BeanFactoryAware接口的类,当它被BeanFactory创建后,它会拥有一个指向创建它的BeanFactory的引用。



public interface BeanFactoryAware {
<wbr><wbr><wbr> void setBeanFactory(BeanFactory beanFactory) throws BeansException;</wbr></wbr></wbr>
}


这允许 bean 可以以编程的方式操控创建它们的 BeanFactory , 既可以直接使用 org.springframework.beans.factory.BeanFactory 接口, 也可以将引用强制将类型转换为已知的子类型从而获得更多的功能。这个特性主要用于编程式地取得其他 bean 。 虽然在一些场景下这个功能是有用的,但是一般来说它应该避免使用,因为它使代码与 Spring 耦合在一起, 而且也不遵循反向控制的风格(合作者应当作属性提供给 bean )。以前我们公司的那套架构中的业务类的工厂类模式( ManagerFactory )就是用此实现,好处很多,提供了统一的获取业务类的接口。因为业务类 Bean 都是 singleton 的,而在 Act<wbr>ion</wbr> 里需要用到业务类来调用业务方法,但是 act<wbr>ion</wbr> 中不可能去 new 一个业务类来(这样 new 出来的业务类没有被容器注入依赖,例如 DAO ),但是如果每次都去直接操作 ApplicationContext, 代码又显得冗余和分层不明确。

模式

解释

no

不使用自动装配。Bean的引用必须通过ref元素定义,在Bean中设置相应的setter。这是默认的配置,在较大的部署环境中不鼓励改变这个配置,因为明确的指定合作者能够得到更多的控制和清晰性。从某种程度上说,这也是系统结构的文档形式。

byName

通过属性名字进行自动装配。这个选项会会检查BeanFactory,查找一个与将要装配的属性同样名字的bean 。比如,你有一个bean的定义被设置为通过名字自动装配,它包含一个master属性(也就是说,它有一个setMaster(...)方法),Spring就会查找一个叫做master的bean定义,然后用它来设置master属性。

byType

如果BeanFactory中正好有一个同属性类型一样的bean,就自动装配这个属性。如果有多于一个这样的bean,就抛出一个致命异常,它指出你可能不能对那个bean使用byType的自动装配。如果没有匹配的bean,则什么都不会发生,属性不会被设置。如果这是你不想要的情况(什么都不发生),通过设置dependency-check="objects"属性值来指定在这种情况下应该抛出错误。

constructor

这个同byType类似,不过是应用于构造函数的参数。如果在BeanFactory中不是恰好有一个bean与构造函数参数相同类型,则一个致命的错误会产生。

autodetect

通过对bean 检查类的内部来选择constructorbyType。如果找到一个缺省的构造函数,那么就会应用byType。