![](http://static.springframework.org/spring/docs/2.0.x/reference/images/xdev-spring_logo.jpg)
![](http://static.springframework.org/spring/docs/2.0.x/reference/images/i21-banner-rhs.jpg)
为什么叫做Bean
?
使用‘bean’这个名字的原因是因为在Spring框架中已经使用了‘componet’和‘object’这些基本概念名称,另外也是由于EJB的复杂性,所以在类似的起了这个名字。
|
在Spring里,组成你应用的核心对象是由IoC容器管理的,被称作beans。一个bean就是一个实例化的、装配好的,且由Spring IoC容器管理的对象;除此之外,关于bean没有什么其他特别的特性。这些bean以及它们之间的依赖由容器的配置元数据来反映(configuration metadata)。
3.2.1
容器
org.springframework.beans.factory.BeanFactory
是
Spring IoC
容器的实际界面,它实际负责包含和管理
bean
。
BeanFactory
接口是
Spring IoC
容器的核心。它的作用包括实例化和初始化应用对象,配置对象和组装对象的依赖。
有很多
BeanFactory
的接口实现。最常用的是
XmlBeanFactory
类,它让你以
XML
方式配置组成应用的对象和这些对象间确定的依赖。
XmlBeanFactory
获取
XML
配置元数据并且按照配置来创建一个完整的系统和应用。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/lifeshow/bff1d2fed41044df939c3ad269f733b8.gif)
Spring IoC
容器示意图
3.2.1
.1
配置元数据(
Configuration metadata
)
从上面的图片可以看出来,Spring IoC容器使用了一些形式的元数据;配置元数据也就是告诉Spring容器,怎样实例化,配置和装配应用对象。配置元数据的形式为简单、直观的XML格式。当使用基于XML的配置元数据时,你需要把那些需要容器管理的bean的定义文件写好,然后让容器去做剩下的事情。
![](https://p-blog.csdn.net/images/p_blog_csdn_net/lifeshow/a15a962145e2425ab2cd32973f8172d8.gif)
XML基础的元数据是到目前为止最常用的配置元数据方式。然后它不是唯一被支持的方式。
Spring容器降低了对于配置元数据的表达格式要求。
在写配置的时候,你可以以XML、Java数据属性格式或者编程方式(利用Spring的公共API)来配置文件。然后XML配置方式是相对简单易用的方式,所以,本章的后面部分将使用XML配置格式来介绍Spring容器的关键概念和特性。
资源:
了解了Spring IoC容器之后,了解“第四章,资源”所介绍的关于Spring的资源抽象(resources abstract)概念是什么必要的。提供给
ApplicationContext
构造器的位置路径实际上是资源串,它用来告诉容器从外部资源加载配置元数据,如本地的文件系统或者是
Java
的
Classpath
等。
|
请记住,在大多数的应用情况下,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定义从
s
ervices.xml
,
messageSource.xml
和
themeSource.xml
三个文件中加载。所有的位置路径是相对于定义文件的,因此
s
ervices.xml
和定义文件必须在相同的路径,而
messageSource.xml
和
themeSource.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'
属性允许你指定一个
bean
的
ID
,由于这是
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
(有默认的(无参数)构造器,并且有合适的
setter
和
getter
方法)放到容器中,当然,也可以将“非
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
,并且读取
Bean
的
XML
定义文件。例如:
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
实例。依据当前
bean
在
BeanFactory
中配置的不同,可能返回单例(共享实例),或者是一个新创建的
bean
实例。如果
bean
不存在,或者正在被初始化,那么方法将返回一个
BeansException
异常(前者将会返回
NoSuchBeanDefinitionException
异常)。
l
Object getBean(String, Class)
:然会一个指定参数的
bean
实例,同时将返回的
bean
强制转换为指定的
Class
类型。如果当前
bean
不能被转换,那么将抛出
BeanNotOfRequiredTypeException
异常。此外,所有
getBeans(String)
的规范也同样适用本方法。
l
Class getType(String name)
:返回指定名称的
bean
的
Class
类型。同样,如果没有找到
bean
,抛出
NoSuchBeanDefinitionException
异常。
l
boolean isSingleton(String)
:判断当前
bean
是否是单例(后面将解释单例)。如果没有找到
bean
,抛出
NoSuchBeanDefinitionException
异常。
l
String[] getAliases(String)
:返回在
bean
定义文件中定义的别名数组。