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

Spring参考手册-第三章 IoC容器-3.2 基本概念-容器和Beans(豆子)

2006-11-08 16:11 483 查看





[b]为什么叫做Bean
使用‘bean’这个名字的原因是因为在Spring框架中已经使用了‘componet’和‘object’这些基本概念名称,另外也是由于EJB的复杂性,所以在类似的起了这个名字。

[/b]
在Spring里,组成你应用的核心对象是由IoC容器管理的,被称作beans。一个bean就是一个实例化的、装配好的,且由SpringIoC容器管理的对象;除此之外,关于bean没有什么其他特别的特性。这些bean以及它们之间的依赖由容器的配置元数据来反映(configurationmetadata)。
3.2.1容器
org.springframework.beans.factory.BeanFactory是SpringIoC容器的实际界面,它实际负责包含和管理bean。
BeanFactory接口是SpringIoC容器的核心。它的作用包括实例化和初始化应用对象,配置对象和组装对象的依赖。
有很多BeanFactory的接口实现。最常用的是XmlBeanFactory类,它让你以XML方式配置组成应用的对象和这些对象间确定的依赖。XmlBeanFactory获取XML配置元数据并且按照配置来创建一个完整的系统和应用。



[align=center]SpringIoC容器示意图[/align]
3.2.1.1配置元数据(Configurationmetadata
从上面的图片可以看出来,SpringIoC容器使用了一些形式的元数据;配置元数据也就是告诉Spring容器,怎样实例化,配置和装配应用对象。配置元数据的形式为简单、直观的XML格式。当使用基于XML的配置元数据时,你需要把那些需要容器管理的bean的定义文件写好,然后让容器去做剩下的事情。


注意:
XML基础的元数据是到目前为止最常用的配置元数据方式。然后它不是唯一被支持的方式。
Spring容器降低了对于配置元数据的表达格式要求。
在写配置的时候,你可以以XML、Java数据属性格式或者编程方式(利用Spring的公共API)来配置文件。然后XML配置方式是相对简单易用的方式,所以,本章的后面部分将使用XML配置格式来介绍Spring容器的关键概念和特性。

资源:
了解了SpringIoC容器之后,了解“第四章,资源”所介绍的关于Spring的资源抽象(resourcesabstract)概念是什么必要的。提供给ApplicationContext构造器的位置路径实际上是资源串,它用来告诉容器从外部资源加载配置元数据,如本地的文件系统或者是Java的Classpath等。

请记住,在大多数的应用情况下,SpringIoC容器是不需要用户代码来实例化的。例如,在典型的J2EE应用中,大约只需要8行左右的XML配置信息即可(web.xml)。
在最基本的情况下,SpringIoC容器配置信息需要包含至少一个bean的定义,实际上大多数情况下都超过一个。当使用XML配置方式时,关于bean的配置内容包含在<bean/>和<beans>元素内。
对应于实际对象的这些bean应用组织起你的应用。一般情况下,你需要定义的bean包括服务层对象,数据访问对象(DAOs),表现层对象(例如StructsAction实例),基础底层对象(HibernateSessionFactory实例),JMS序列(Queue)引用等。(当然,还有很多其他的可能需要配置的信息,这取决于你的应用复杂度)。
下面就是一个XML配置的典型例子。

<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

http://www.springframework.org/schema/beans'target='_blank'>http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">[/code]
<beanid="..."class="...">

<!--collaboratorsandconfigurationforthisbeangohere-->

</bean>

<beanid="..."class="...">

<!--collaboratorsandconfigurationforthisbeangohere-->

</bean>

<!--morebeandefinitionsgohere...-->

</beans>


3.2.2初始化容器
初始化Spring容器十分方便;参看下面的例子。
例1:

Resourceresource=newFileSystemResource("beans.xml");

BeanFactoryfactory=newXmlBeanFactory(resource);


例2:

ClassPathResourceresource=newClassPathResource("beans.xml");

BeanFactoryfactory=newXmlBeanFactory(resource);


例3:

ApplicationContextcontext=newClassPathXmlApplicationContext(

newString[]{"applicationContext.xml","applicationContext-part2.xml"});

//ofcourse,anApplicationContextisjustaBeanFactory

BeanFactoryfactory=(BeanFactory)context;


3.2.2.1组织XML配置文件
将容器配置文件分解成多个XML配置文件是什么有用的。加载多个XML文件的方法之一是利用应用上下文(applicationcontext)的构造器来读取多个资源(Resource)位置。利用beanfactory,一个bean的定义读取器(reader)可以在读取每个配置文件的时候重复使用。
一般来说,Spring团队推荐上面的方法,因为这种方法使得配置文件的读取对于容器是透明的。另外一个替代的方法是在定义文件中使用<import>元素来定义其他的bean定义文件。<import/>元素必须放置在<bean/>元素之前。参看下面的例子:

<beans>

<importresource="services.xml"/>

<importresource="resources/messageSource.xml"/>

<importresource="/resources/themeSource.xml"/>

<beanid="bean1"class="..."/>

<beanid="bean2"class="..."/>

</beans>


本例中,外部的bean定义从services.xml,messageSource.xml和themeSource.xml三个文件中加载。所有的位置路径是相对于定义文件的,因此services.xml和定义文件必须在相同的路径,而messageSource.xml和themeSource.xml是在相对路径的resources目录下面。可以看出,路径开头的/已经被省略,这些路径被认为是相对路径,或许这是种更好的方式。
导入的配置文件内容必须符合包含在定义文件头部的Schema或者DTD的合法性验证。
3.2.3Beans
正如前面所述,SpringIoC容器管理一个或者多个Bean。容器按照定义的配置元数据(典型的为XML的bean定义文件)来创建bean。
在容器内部,这些bean的定义被表示成BeanDefinition对象,其中包含以下的元数据:
l一个类名(包含包定义):这实际上是这个bean的实现类。然而,如果这个bean是通过调用静态的工厂方法创建的(而不是通过正常的构造器创建的),这个实际上是这个工厂类的名字。
lBean的行为配置元素,用来告诉容器bean在容器中的行为(如原型、单例、自装配模式、依赖检查模式以及初始化(initialization)和消除(destruction)方法)。
l新创建的bean的构造器参数和属性值。例如bean中用来管理的连接池数量(可以作为属性指定,也可以作为构造器参数),或者连接池大小。
lBean正常运行所需要的其他的bean说明,例如合作者(或者叫依赖)。
上面提到的概念在定义文件中对应于bean定义的属性集合。下面给出了一些属性的详细文档链接。
3.1.bean定义
[align=center]Feature[/align]
[align=center]Explainedin...[/align]
class
Section3.2.3.2,“Instantiatingbeans”
name
Section3.2.3.1,“Namingbeans”
scope
Section3.4,“Beanscopes”
constructorarguments
Section3.3.1,“Injectingdependencies”
properties
Section3.3.1,“Injectingdependencies”
autowiringmode
Section3.3.6,“Autowiringcollaborators”
dependencycheckingmode
Section3.3.7,“Checkingfordependencies”
lazy-initializationmode
Section3.3.5,“Lazily-instantiatingbeans”
initializationmethod
Section3.5.1,“Lifecycleinterfaces”
destructionmethod
Section3.5.1,“Lifecycleinterfaces”
除了通过bean定义文件来创建bean以外,某些BeanFactory实现也允许注册那些已经在工厂之外创建的对象(通过用户代码创建)。DefaultListableBeanFactory类就支持registerSingleton(..)方法。然而,典型的应用一般还是通过bean定义的方式来实现bean的创建和管理。
3.2.3.1命名Beans

Bean的命名规范:
Bean的命名规范(至少在Spring开发团队中是这样)是使用标准的Java命名规范。具体规范如下,bean的名字以小写字母开头,并且是camel-cased。例如:'accountManager','accountService','userDao','loginController'等等。按照统一的方式来命名bean,将会使得你的配置内容更易于阅读和理解;采用这样的命名规范并不困难,采用SpringAOP框架的时候,它可以在bean的命名方面给与很多提示和建议。

每个bean都有一个或者多个标识(也叫标识符,或者名字;这些指的都是同样的东西)。这些标识符在容器中必须是唯一的。通常bean只有一个标识,但当bean有超过一个标识时,其他的标识可以看作是别名。
使用XML配置文件时,使用'id'或者'name'来指定bean的标识。'id'属性允许你指定一个bean的ID,由于这是XML元素的ID属性,XML解析器能够在别的元素引用这个ID的时候做完全的验证。然而,XML规范限制了XMLID中使用的字符类型。通常这不会造成影响,但如果你需要使用特定的XML字符,或者为bean取别名的时候,你可以在'name'属性中指定多个标识,标识之间以逗号(,),分号(;)或者空格分隔。
注意,你并不一定要为bean命名。如果没有命名,容器将会为bean创建一个唯一的名字。不命名bean的目的将会在后面讨论(一种情况是内部bean-innerbeans)。
3.2.3.1.1Bean别名
在bean定义中,你可以通过ID属性指定bean的名字,然后再通过alias属性来指定bean的别名。所有的名字指向同一个bean,这在有些情况下很有用,允许应用的组件使用与组件名字有关的bean别名来引用bean。
然后,在bean定义的时候,就必须要指定所有的别名似乎不太合适。有的时候为在其他地方定义的bean来定义一个别名是什么必要的。在XML配置方式中,可以通过独立(standalone)的<alias/>元素来实现这点。例如:

<aliasname="fromName"alias="toName"/>


上面的例子中,在同一容器的bean叫做'fromName',在使用上面的别名定义之后,可以用'toName'来引用这个bean。
举个具体的例子,例如组件A在它的XML配置中定义了一个DataSourcebean叫做componentA-dataSource。组件B希望在它的配置中用componentB-dataSource来引用这个bean。同时,主应用MyApp则定义了自己的XML配置,并且装配了来自三个不同XML配置的应用上下文,要用myApp-dataSource来引用bean。对于这种情况可以在用下面的配置方式很方便的实现:

<aliasname="componentA-dataSource"

alias="componentB-dataSource"/>

<aliasname="componentA-dataSource"alias="myApp-dataSource"/>


现在每个组件,包括主应用都以一个不会和其他定义发生冲突的名字来应用这个dataSource了。
3.2.3.2初始化bean
在SpringIoC容器中,bean的定义配置是创建一个或者多个实际对象的依据。容器参照bean定义并且使用配置数据来定义和创建一个实际的对象。本章关注的是对于作为开发者的你来说,怎样去告知SpringIoC容器要初始化的对象类型是什么,怎样去初始化对象。
如果你使用XML配置方式,你可以用’class’属性来指定对象的类型。’class’属性(在容器的BeanDefinition实例中表示为Class属性)是必须的(参照第3.2.3.2.2-“使用实例工厂方法来初始化”和第3.6章-“Bean定义继承”),并且有两个目的。大多数情况下,Class属性告知容器去哪儿以反射方式调用构造器来创建bean实例(类似于java的’new’方法)。
在调用静态工厂方法创建bean的情况下,class属性指定的是包含静态工厂方法的类(返回的对象类型可能是同一个类,也可能是另外的类,这无关紧要)。
3.2.3.2.1使用constructor实例化bean
当使用构造器来创建bean的时候,Spring支持对于大多数的常规的类的创建。也就是说,这些类不需要实现特定的接口,或者要求以特定的方式来编码。只要指定bean的类就可以。然后,依赖于IoC容器的类型,你可能需要一个默认(空的)构造器。
SpringIoC容器除了管理JavaBean以外,也可以虚拟地管理你要管理的任何类。大多数使用Spring的人更细化将真正的JavaBean(有默认的(无参数)构造器,并且有合适的setter和getter方法)放到容器中,当然,也可以将“非bean类型”(non-bean-style)的类放在容器中。例如,当你要使用一个完全不符合JavaBean规范的连接池对象的时候,Spring同样可以很好的管理。
在XML配置中,可以用如下的方式来定义bean:

<beanid="exampleBean"class="examples.ExampleBean"/>

<beanname="anotherExample"class="examples.ExampleBeanTwo"/>


如何指定构造器参数(如果需要的话),或者如何设置对象实例的属性,这些将稍后描述。
3.2.3.2.2使用静态工厂方法(staticfactorymethod)实例化bean
当使用静态工厂方法来定义bean时,class属性指定包含静态工厂方法的类,factory-method属性用来指定工厂方法名。Spring调用工厂方法(调用可选的参数列表,后面介绍)然后返回一个活动的对象,在外面看来和利用构造器方法创建bean实例一样。这种创建方法的一个用处是在代码中调用静态工厂方法。
下面的例子说明了通过工厂方法来创建bean的定义文件。注意下面的定义并没有指定返回对象的类型,只指定了工厂方法。例子中的createInstance()方法必须是一个静态方法。

<beanid="exampleBean"

class="examples.ExampleBean2"

factory-method="createInstance"/>


静态工厂方法的参数(可选)制定方法和对象实例的属性设置方法(setter)将在后面说明。
3.2.3.2.3使用实例工厂方法(instancefactorymethod)实例化bean
有点类似于静态工厂方法,实例工厂方法是通过调用容器中存在的bean实例的工厂方法来创建新的bean。
要用这个方法创建bean,’class’属性必须为空,而’factory-bean’属性必须指定当前容器(或者父容器)中包含了工厂方法的bean的名字。而工厂方法的名字同过’factory-method’属性指定。(参看下面的例子)

<!--thefactorybean,whichcontainsamethodcalledcreateInstance()-->

<beanid="myFactoryBean"class="...">

...

</bean>


<!--thebeantobecreatedviathefactorybean-->

<beanid="exampleBean"

factory-bean="myFactoryBean"

factory-method="createInstance"/>


尽管这种方法设置bean属性的机制当前仍然在讨论,但一个可能的好处是工厂bean自身可以被管理,同时可以用依赖注射(DI)的方式来配置它。
3.2.4使用容器
BeanFactory只不过是一个能够维护不同的bean以及它们之间关系的注册的高级工厂的接口。BeanFactory使得你可以读取bean定义文件并且访问它们。当只使用BeanFactory的时候,你需要创建一个BeanFactory,并且读取Bean的XML定义文件。例如:

InputStreamis=newFileInputStream("beans.xml");

BeanFactoryfactory=newXmlBeanFactory(is);


上面基本就是创建容器要做的一切。利用getBean(String)方法,你可以检索bean的实例;BeanFactory的客户端接口相当简单,仅仅有六个供客户代码调用的接口:
lbooleancontainsBean(String):如果BeanFactory包含匹配参数的bean定义或者bean实例,则返回true。
lObjectgetBean(String):按照指定的参数返回bean实例。依据当前bean在BeanFactory中配置的不同,可能返回单例(共享实例),或者是一个新创建的bean实例。如果bean不存在,或者正在被初始化,那么方法将返回一个BeansException异常(前者将会返回NoSuchBeanDefinitionException异常)。
lObjectgetBean(String,Class):然会一个指定参数的bean实例,同时将返回的bean强制转换为指定的Class类型。如果当前bean不能被转换,那么将抛出BeanNotOfRequiredTypeException异常。此外,所有getBeans(String)的规范也同样适用本方法。
lClassgetType(Stringname):返回指定名称的bean的Class类型。同样,如果没有找到bean,抛出NoSuchBeanDefinitionException异常。
lbooleanisSingleton(String):判断当前bean是否是单例(后面将解释单例)。如果没有找到bean,抛出NoSuchBeanDefinitionException异常。
lString[]getAliases(String):返回在bean定义文件中定义的别名数组。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: