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

 

为什么叫做Bean
使用‘bean’这个名字的原因是因为在Spring框架中已经使用了‘componet’和‘object’这些基本概念名称,另外也是由于EJB的复杂性,所以在类似的起了这个名字。
 在Spring里,组成你应用的核心对象是由IoC容器管理的,被称作beans。一个bean就是一个实例化的、装配好的,且由Spring IoC容器管理的对象;除此之外,关于bean没有什么其他特别的特性。这些bean以及它们之间的依赖由容器的配置元数据来反映(configuration metadata)。
3.2.1容器
org.springframework.beans.factory.BeanFactorySpring IoC容器的实际界面,它实际负责包含和管理bean
BeanFactory接口是Spring IoC容器的核心。它的作用包括实例化和初始化应用对象,配置对象和组装对象的依赖。
 有很多BeanFactory的接口实现。最常用的是XmlBeanFactory类,它让你以XML方式配置组成应用的对象和这些对象间确定的依赖。XmlBeanFactory获取XML配置元数据并且按照配置来创建一个完整的系统和应用。
Spring IoC容器示意图
3.2.1.1 配置元数据(Configuration metadata
 从上面的图片可以看出来,Spring IoC容器使用了一些形式的元数据;配置元数据也就是告诉Spring容器,怎样实例化,配置和装配应用对象。配置元数据的形式为简单、直观的XML格式。当使用基于XML的配置元数据时,你需要把那些需要容器管理的bean的定义文件写好,然后让容器去做剩下的事情。
注意:
XML基础的元数据是到目前为止最常用的配置元数据方式。然后它不是唯一被支持的方式。
Spring容器降低了对于配置元数据的表达格式要求。
在写配置的时候,你可以以XML、Java数据属性格式或者编程方式(利用Spring的公共API)来配置文件。然后XML配置方式是相对简单易用的方式,所以,本章的后面部分将使用XML配置格式来介绍Spring容器的关键概念和特性。

资源:
了解了Spring IoC容器之后,了解“第四章,资源”所介绍的关于Spring的资源抽象(resources abstract)概念是什么必要的。提供给ApplicationContext构造器的位置路径实际上是资源串,它用来告诉容器从外部资源加载配置元数据,如本地的文件系统或者是JavaClasspath等。
 请记住,在大多数的应用情况下,Spring IoC容器是不需要用户代码来实例化的。例如,在典型的J2EE应用中,大约只需要8行左右的XML配置信息即可(web.xml)。
 在最基本的情况下,Spring IoC容器配置信息需要包含至少一个bean的定义,实际上大多数情况下都超过一个。当使用XML配置方式时,关于bean的配置内容包含在<bean/>和<beans>元素内。
 对应于实际对象的这些bean应用组织起你的应用。一般情况下,你需要定义的bean包括服务层对象,数据访问对象(DAOs),表现层对象(例如Structs Action实例),基础底层对象(Hibernate SessionFactory实例),JMS序列(Queue)引用等。(当然,还有很多其他的可能需要配置的信息,这取决于你的应用复杂度)。
 下面就是一个XML配置的典型例子。
 
 
 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
 </bean>
 <bean id="..." class="...">
    <!-- collaborators and configuration for this bean go here -->
 </bean>
 <!-- more bean definitions go here... -->
</beans>
3.2.2初始化容器
 初始化Spring容器十分方便;参看下面的例子。
例1:
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
例2:
 
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
例3:
ApplicationContext context = new ClassPathXmlApplicationContext(
        new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
// of course, an ApplicationContext is just a BeanFactory
BeanFactory factory = (BeanFactory) context;
3.2.2.1 组织XML配置文件
 将容器配置文件分解成多个XML配置文件是什么有用的。加载多个XML文件的方法之一是利用应用上下文(application context)的构造器来读取多个资源(Resource)位置。利用bean factory,一个bean的定义读取器(reader)可以在读取每个配置文件的时候重复使用。
 一般来说,Spring团队推荐上面的方法,因为这种方法使得配置文件的读取对于容器是透明的。另外一个替代的方法是在定义文件中使用<import>元素来定义其他的bean定义文件。<import/>元素必须放置在<bean/>元素之前。参看下面的例子:
<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>
    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>
本例中,外部的bean定义从services.xmlmessageSource.xmlthemeSource.xml三个文件中加载。所有的位置路径是相对于定义文件的,因此services.xml和定义文件必须在相同的路径,而messageSource.xmlthemeSource.xml是在相对路径的resources目录下面。可以看出,路径开头的/已经被省略,这些路径被认为是相对路径,或许这是种更好的方式。
 导入的配置文件内容必须符合包含在定义文件头部的Schema或者DTD的合法性验证。
3.2.3 Beans
 正如前面所述,Spring IoC容器管理一个或者多个Bean。容器按照定义的配置元数据(典型的为XML的bean定义文件)来创建bean。
 在容器内部,这些bean的定义被表示成BeanDefinition对象,其中包含以下的元数据:
l         一个类名(包含包定义):这实际上是这个bean的实现类。然而,如果这个bean是通过调用静态的工厂方法创建的(而不是通过正常的构造器创建的),这个实际上是这个工厂类的名字。
l         Bean的行为配置元素,用来告诉容器bean在容器中的行为(如原型、单例、自装配模式、依赖检查模式以及初始化(initialization)和消除(destruction)方法)。
l         新创建的bean的构造器参数和属性值。例如bean中用来管理的连接池数量(可以作为属性指定,也可以作为构造器参数),或者连接池大小。
l         Bean正常运行所需要的其他的bean说明,例如合作者(或者叫依赖)。
上面提到的概念在定义文件中对应于bean定义的属性集合。下面给出了一些属性的详细文档链接。
 3.1. bean定义
Feature
Explained in...
class
name
scope
constructor arguments
properties
autowiring mode
dependency checking mode
lazy-initialization mode
initialization method
destruction method
 除了通过bean定义文件来创建bean以外,某些BeanFactory实现也允许注册那些已经在工厂之外创建的对象(通过用户代码创建)。DefaultListableBeanFactory类就支持registerSingleton(..)方法。然而,典型的应用一般还是通过bean定义的方式来实现bean的创建和管理。
3.2.3.1 命名Beans

Bean的命名规范:
Bean的命名规范(至少在Spring开发团队中是这样)是使用标准的Java命名规范。具体规范如下,bean的名字以小写字母开头,并且是camel-cased。例如:'accountManager', 'accountService', 'userDao', 'loginController'等等。按照统一的方式来命名bean,将会使得你的配置内容更易于阅读和理解;采用这样的命名规范并不困难,采用Spring AOP框架的时候,它可以在bean的命名方面给与很多提示和建议。
每个bean都有一个或者多个标识(也叫标识符,或者名字;这些指的都是同样的东西)。这些标识符在容器中必须是唯一的。通常bean只有一个标识,但当bean有超过一个标识时,其他的标识可以看作是别名。
使用XML配置文件时,使用'id'或者'name'来指定bean的标识。'id'属性允许你指定一个beanID,由于这是XML元素的ID属性,XML解析器能够在别的元素引用这个ID的时候做完全的验证。然而,XML规范限制了XML ID中使用的字符类型。通常这不会造成影响,但如果你需要使用特定的XML字符,或者为bean取别名的时候,你可以在'name'属性中指定多个标识,标识之间以逗号(,),分号(;)或者空格分隔。
注意,你并不一定要为bean命名。如果没有命名,容器将会为bean创建一个唯一的名字。不命名bean的目的将会在后面讨论(一种情况是内部bean-inner beans)。
3.2.3.1.1 Bean别名
bean定义中,你可以通过ID属性指定bean的名字,然后再通过alias属性来指定bean的别名。所有的名字指向同一个bean,这在有些情况下很有用,允许应用的组件使用与组件名字有关的bean别名来引用bean
然后,在bean定义的时候,就必须要指定所有的别名似乎不太合适。有的时候为在其他地方定义的bean来定义一个别名是什么必要的。在XML配置方式中,可以通过独立(standalone)的<alias/>元素来实现这点。例如:
<alias name="fromName" alias="toName"/>
上面的例子中,在同一容器的bean叫做'fromName',在使用上面的别名定义之后,可以用'toName'来引用这个bean
举个具体的例子,例如组件A在它的XML配置中定义了一个DataSource bean叫做componentA-dataSource。组件B希望在它的配置中用componentB-dataSource来引用这个bean。同时,主应用MyApp则定义了自己的XML配置,并且装配了来自三个不同XML配置的应用上下文,要用myApp-dataSource来引用bean。对于这种情况可以在用下面的配置方式很方便的实现:
<alias name="componentA-dataSource"
 alias="componentB-dataSource"/>
<alias name="componentA-dataSource" alias="myApp-dataSource" />
现在每个组件,包括主应用都以一个不会和其他定义发生冲突的名字来应用这个dataSource了。
3.2.3.2 初始化bean
Spring IoC容器中,bean的定义配置是创建一个或者多个实际对象的依据。容器参照bean定义并且使用配置数据来定义和创建一个实际的对象。本章关注的是对于作为开发者的你来说,怎样去告知Spring IoC容器要初始化的对象类型是什么,怎样去初始化对象。
如果你使用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容器的类型,你可能需要一个默认(空的)构造器。
Spring IoC容器除了管理JavaBean以外,也可以虚拟地管理你要管理的任何类。大多数使用Spring的人更细化将真正的JavaBean(有默认的(无参数)构造器,并且有合适的settergetter方法)放到容器中,当然,也可以将“非bean类型”(non-bean-style)的类放在容器中。例如,当你要使用一个完全不符合JavaBean规范的连接池对象的时候,Spring同样可以很好的管理。
XML配置中,可以用如下的方式来定义bean
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
如何指定构造器参数(如果需要的话),或者如何设置对象实例的属性,这些将稍后描述。
3.2.3.2.2 使用静态工厂方法(static factory method)实例化bean
当使用静态工厂方法来定义bean时,class属性指定包含静态工厂方法的类,factory-method属性用来指定工厂方法名。Spring调用工厂方法(调用可选的参数列表,后面介绍)然后返回一个活动的对象,在外面看来和利用构造器方法创建bean实例一样。这种创建方法的一个用处是在代码中调用静态工厂方法。
下面的例子说明了通过工厂方法来创建bean的定义文件。注意下面的定义并没有指定返回对象的类型,只指定了工厂方法。例子中的createInstance()方法必须是一个静态方法。
<bean id="exampleBean"
      class="examples.ExampleBean2"
      factory-method="createInstance"/>
静态工厂方法的参数(可选)制定方法和对象实例的属性设置方法(setter)将在后面说明。
3.2.3.2.3 使用实例工厂方法(instance factory method)实例化bean
有点类似于静态工厂方法,实例工厂方法是通过调用容器中存在的bean实例的工厂方法来创建新的bean
要用这个方法创建bean’class’属性必须为空,而’factory-bean’属性必须指定当前容器(或者父容器)中包含了工厂方法的bean的名字。而工厂方法的名字同过’factory-method’属性指定。(参看下面的例子)
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="myFactoryBean" class="...">
 ...
</bean>
 
<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
      factory-bean="myFactoryBean"
      factory-method="createInstance"/>
尽管这种方法设置bean属性的机制当前仍然在讨论,但一个可能的好处是工厂bean自身可以被管理,同时可以用依赖注射(DI)的方式来配置它。
3.2.4使用容器
BeanFactory只不过是一个能够维护不同的bean以及它们之间关系的注册的高级工厂的接口。BeanFactory使得你可以读取bean定义文件并且访问它们。当只使用BeanFactory的时候,你需要创建一个BeanFactory,并且读取BeanXML定义文件。例如:
InputStream is = new FileInputStream("beans.xml");
BeanFactory factory = new XmlBeanFactory(is);
上面基本就是创建容器要做的一切。利用getBean(String)方法,你可以检索bean的实例;BeanFactory的客户端接口相当简单,仅仅有六个供客户代码调用的接口:
l        boolean containsBean(String):如果BeanFactory包含匹配参数的bean定义或者bean实例,则返回true
l        Object getBean(String):按照指定的参数返回bean实例。依据当前beanBeanFactory中配置的不同,可能返回单例(共享实例),或者是一个新创建的bean实例。如果bean不存在,或者正在被初始化,那么方法将返回一个BeansException异常(前者将会返回NoSuchBeanDefinitionException异常)。
l        Object getBean(String, Class):然会一个指定参数的bean实例,同时将返回的bean强制转换为指定的Class类型。如果当前bean不能被转换,那么将抛出BeanNotOfRequiredTypeException异常。此外,所有getBeans(String)的规范也同样适用本方法。
l        Class getType(String name):返回指定名称的beanClass类型。同样,如果没有找到bean,抛出NoSuchBeanDefinitionException异常。
l        boolean isSingleton(String):判断当前bean是否是单例(后面将解释单例)。如果没有找到bean,抛出NoSuchBeanDefinitionException异常。
l        String[] getAliases(String):返回在bean定义文件中定义的别名数组。
发布了28 篇原创文章 · 获赞 6 · 访问量 13万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章