原贴地址:http://book.csdn.net/bookfiles/111/1001113461.shtml
一.Spring IOC反转控制 BeanFactory
Spring IoC
设计的核心是
org.springframework.beans
包,它的设计目标是与
JavaBean
组件一起使用。这个包通常不是由用户直接使用,而是由服务器将其用作其他多数功能的底层中介。下一个最高级抽象是
BeanFactory
接口,它是工厂设计模式的实现,允许通过名称创建和检索对象。
BeanFactory
也可以管理对象之间的关系。
BeanFactory
支持两个对象模型。
单态模型:它提供了具有特定名称的对象的共享实例,可以在查询时对其进行检索。
Singleton
是默认的也是最常用的对象模型,对于无状态服务对象很理想。
原型模型:它确保每次检索都会创建单独的对象。在每个用户都需要自己的对象时,原型模型最适合。
bean
工厂的概念是
Spring
作为
IoC
容器的基础,
IoC
将处理事情的责任从应用程序代码转移到框架。
Spring
框架使用
JavaBean
属性和配置数据来指出必须设置的依赖关系。
1
.
BeanFactory
BeanFactory
实际上是实例化,配置和管理众多
bean
的容器。这些
bean
通常会彼此合作,因而它们之间会产生依赖。
BeanFactory
使用的配置数据可以反映这些依赖关系(一些依赖可能不像配置数据一样可见,而是在运行期作为
bean
之间程序交互的函数)。
一个
BeanFactory
可以用接口
org.springframework.beans.factory.BeanFactory
表示,这个接口有多个实现。最常使用的简单的
BeanFactory
实现是
org.springframework.beans.factory. xml.XmlBeanFactory
(这里提醒一下,
ApplicationContext
是
BeanFactory
的子类,所以大多数的用户更喜欢使用
ApplicationContext
的
XML
形式)。
虽然大多数情况下,几乎所有被
BeanFactory
管理的用户代码都不需要知道
BeanFactory
,但是
BeanFactory
还是以某种方式实例化。可以使用下面的代码实例化
BeanFactory
。
InputStream is = new FileInputStream("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
也可以使用下列代码实例化
BeanFactory
。
ClassPathResource res = new ClassPathResource("beans.xml");
XmlBeanFactory factory = new XmlBeanFactory(res);
实例化
BeanFactory
还可以采用如下代码。
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplication Context(
new String[] {"applicationContext.xml", "applicationContext-part2. xml"});
// of course, an ApplicationContext is just a BeanFactory
BeanFactory factory = (BeanFactory) appContext;
很多情况下,用户代码不需要实例化
BeanFactory
,因为
Spring
框架代码会做这件事。例如,
Web
层提供支持代码,在
J2EE Web
应用启动过程中自动载入一个
Spring ApplicationContext
。这个声明过程在这里描述。
编程操作
BeanFactory
将会在后面提到,下面部分将集中描述
BeanFactory
的配置。
一个最基本的
BeanFactory
配置由一个或多个它所管理的
Bean
定义组成。在一个
XmlBeanFactory
中,根节点
beans
中包含一个或多个
bean
元素。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework. org/dtd/spring-beans.dtd">
<beans>
<bean id="..." class="...">
...
</bean>
<bean id="..." class="...">
...
</bean>
</beans>
...
2
.
BeanDefinition
一个
XmlBeanFactory
中的
Bean
定义包括的内容如下。
classname
:这通常是
bean
真正的实现类。但是,如果一个
bean
使用一个静态工厂方法所创建,而不是被普通的构造函数创建,那么这实际上就是工厂类的
classname
。
bean
行为配置元素:它声明这个
bean
在容器的行为方式(比如
prototype
或
singleton
、自动装配模式、依赖检查模式、初始化和析构方法)。
构造函数的参数和新创建
bean
需要的属性:举一个例子,一个管理连接池的
bean
使用的连接数目(即可以指定为一个属性,也可以作为一个构造函数参数)或者池的大小限制。
和这个
bean
工作相关的其他
bean
:比如它的合作者(同样可以作为属性或者构造函数的参数),这个也被叫做依赖。
上面列出的概念直接转化为组成
bean
定义的一组元素。这些元素在表
6-1
中列出,它们每一个都有更详细的说明的链接。
表
6-1 Bean
定义的解释
特
性
|
说
明
|
class
|
bean
的类
|
id
和
name
|
bean
的标志符
(id
与
name)
|
singleton
或
prototype
|
Singleton
的使用与否
|
构造函数参数
|
设置
bean
的属性和合作者
|
bean
的属性
|
设置
bean
的属性和合作者
|
自动装配模式
|
自动装配协作对象
|
依赖检查模式
|
依赖检查
|
初始化模式
|
生命周期接口
|
析构方法
|
生命周期接口
|
注
意,
bean
定义可以表示为真正的接口
org.springframework.beans.factory.config.BeanDefinition
以及它的各种子接口和实现。然而,绝大多数的用户代码不需要与
BeanDefination
直接接触。
3
.
bean
类
class
属性通常是强制性的,有两种用法。在绝大多数情况下,
BeanFactory
直接调用
bean
的构造函数来“
new
”一个
bean
(相当于调用
new
的
Java
代码),
class
属性指定了需要创建的
bean
的类。在比较少的情况下,
BeanFactory
调用某个类的静态的工厂方法来创建
bean
,
class
属性指定了实际包含静态工厂方法的那个类(至于静态工厂方法返回的
bean
的类型是同一个类还是完全不同的另一个类,这并不重要)。
1
)通过构造函数创建
bean
当使用构造函数创建
bean
时,所有普通的类都可以被
Spring
使用,并且和
Spring
兼容。这就是说,被创建的类不需要实现任何特定的接口或者按照特定的样式进行编写。仅仅指定
bean
的类就足够了。然而,根据
bean
使用的
IoC
类型,你可能需要一个默认的(空的)构造函数。
另外,
BeanFactory
并不局限于管理真正的
JavaBean
,它也能管理任何你想让它管理的类。虽然很多使用
Spring
的人喜欢在
BeanFactory
中用真正的
JavaBean
(仅包含一个默认的(无参数的)构造函数,在属性后面定义相对应的
setter
和
getter
方法),但是在你的
BeanFactory
中也可以使用特殊的非
bean
样式的类。举例来说,如果你需要使用一个遗留下来的完全没有遵守
JavaBean
规范的连接池,不要担心,
Spring
同样能够管理它。
使用
XmlBeanFactory
你可以像下面这样定义你的
bean class
。
<bean id="exampleBean"
class="examples.ExampleBean"/>
<bean name="anotherExample"
class="examples.ExampleBeanTwo"/>
至于为构造函数提供(可选的)参数,以及对象实例创建后设置实例属性,将会在后面叙述。
2
)通过静态工厂方法创建
bean
当你定义一个使用静态工厂方法创建的
bean
,同时使用
class
属性指定包含静态工厂方法的类,这个时候需要
factory-method
属性来指定工厂方法名。
Spring
调用这个方法(包含一组可选的参数)并返回一个有效的对象,之后这个对象就完全和构造方法创建的对象一样。用户可以使用这样的
bean
定义在遗留代码中调用静态工厂。
下面是一个
bean
定义的例子,声明这个
bean
要通过
factory-method
指定的方法创建。注意,这个
bean
定义并没有指定返回对象的类型,只指定包含工厂方法的类。在这个例子中,
createInstance
必须是
static
方法。
<bean id="exampleBean"
class="examples.ExampleBean2"
factory-method="createInstance"/>
至于为工厂方法提供(可选的)参数,以及对象实例被工厂方法创建后设置实例属性,将会在后面叙述。
3
)通过实例工厂方法创建
bean
使用一个实例工厂方法(非静态的)创建
bean
和使用静态工厂方法非常类似,调用一个已存在的
bean
(这个
bean
应该是工厂类型)的工厂方法来创建新的
bean
。
使用这种机制,
class
属性必须为空,而且
factory-bean
属性必须指定一个
bean
的名字,这个
bean
一定要在当前的
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
本身能够被容器通过依赖注射来管理和配置。
4
.
Bean
的标志符(
id
与
name
)
每一个
bean
都有一个或多个
id
(也叫做标志符或名字,这些名词说的是一回事)。这些
id
在管理
bean
的
BeanFactory
或
ApplicationContext
中必须是惟一的。一个
bean
差不多总是只有一个
id
,但是,如果一个
bean
有超过一个的
id
,那么另外的那些本质上可以认为是别名。
在一个
XmlBeanFactory
中(包括
ApplicationContext
的形式),你可以用
id
或者
name
属性来指定
bean
的
id(s)
,并且在这两个或其中一个属性中至少指定一个
id
。
id
属性允许你指定一个
id
,并且它在
XML DTD
(定义文档)中作为一个真正的
XML
元素的
ID
属性被标记,所以
XML
解析器能够在其他元素指回向它的时候做一些额外的校验。正因如此,用
id
属性指定
bean
的
id
是一个比较好的方式。然而,
XML
规范严格限定了在
XML ID
中合法的字符。通常这并不是真正限制你,但是,如果你有必要使用这些字符(在
ID
中的非法字符),或者你想给
bean
增加其他的别名,那么你可以通过
name
属性指定一个或多个
id
(用逗号或分号分隔)。
5
.
Singleton
的使用与否
Beans
被定义为两种部署模式中的一种:
singleton
或
non-singleton
(后一种也叫做
prototype
,尽管这个名词用的不精确)。如果一个
bean
是
singleton
形态的,那么就只有一个共享的实例存在,所有和这个
bean
定义的
id
符合的
bean
请求都会返回这个惟一的、特定的实例。
如果
bean
以
non-singleton
、
prototype
模式部署的话,对这个
bean
的每次请求都会创建一个新的
bean
实例。这对于每个
user
需要一个独立的
user
对象的情况是非常理想的。
Beans
默认被部署为
singleton
模式,除非你指定。要记住把部署模式变为
non-singletion
(
prototype
)后,每一次对这个
bean
的请求都会导致一个新创建的
bean
,而这可能并不是你真正想要的。所以,仅仅在绝对需要的时候才把模式改成
prototype
。
在下面这个例子中,两个
bean
一个被定义为
singleton
,而另一个被定义为
non-singleton
(
prototype
)。客户端每次向
BeanFactory
请求都会创建新的
exampleBean
,而
AnotherExample
仅仅被创建一次,在每次对它请求都会返回这个实例的引用。
<bean id="exampleBean"
class="examples.ExampleBean" singleton="false"/>
<bean name="yetAnotherExample"
class="examples.ExampleBeanTwo" singleton="true"/>
注意,当部署一个
bean
为
prototype
模式,这个
bean
的生命周期就会有稍许改变。
通过定义,
Spring
无法管理一个
non-singleton/prototype bean
的整个生命周期,因为当它创建之后,它被交给客户端,而且容器根本不再跟踪它了。当说起
non-singleton/prototype bean
的时候,你可以把
Spring
的角色想像成“
new
”操作符的替代品。从那之后的任何生命周期方面的事情都由客户端来处理。
二.Spring IOC反转控制 ApplicationContext
beans
包提供了以编程的方式管理和操控
bean
的基本功能,而
context
包增加了
ApplicationContext
,它以一种更加面向框架的方式增强了
BeanFactory
的功能。多数用户可以以一种完全的声明式方式来使用
ApplicationContext
,甚至不用去手工创建它,但是却去依赖像
ContextLoader
的支持类,在
J2EE
的
Web
应用的启动进程中用它启动
ApplicationContext
。当然,这种情况下还可以以编程的方式创建一个
ApplicationContext
。
Context
包的基础是位于
org.springframework.context
包中的
ApplicationContext
接口。它是由
BeanFactory
接口集成而来,提供
BeanFactory
所有的功能。为了以一种更像面向框架的方式工作,
context
包使用分层和有继承关系的上下文类,包括:
1
.
MessageSource
,提供对
i18n
消息的访问;
2
.资源访问,比如
URL
和文件;
3
.事件传递给实现了
ApplicationListener
接口的
bean
;
4
.载入多个(有继承关系)上下文类,使得每一个上下文类都专注于一个特定的层次,比如应用的
Web
层。
因为
ApplicationContext
包括了
BeanFactory
所有的功能,所以通常建议先于
BeanFactory
使用,除了有限的一些场合,比如在一个
Applet
中,内存的消耗是关键的,每千字节都很重要。接下来,叙述
ApplicationContext
在
BeanFactory
的基本能力上增加的功能。
(
1
)使用
MessageSource
ApplicationContext
接口继承
MessageSource
接口,所以提供了
messaging
功能(
i18n
或者国际化)。同
NestingMessageSource
一起使用,就能够处理分级的信息,这些是
Spring
提供的处理信息的基本接口。让我们很快浏览一下这里定义的方法。
String getMessage (String code
、
Object[] args
、
String default
、
Locale loc)
:这个方法是从
MessageSource
取得信息的基本方法。如果对于指定的
locale
没有找到信息,则使用默认的信息。传入的参数
args
被用来代替信息中的占位符,这个是通过
Java
标准类库的
MessageFormat
实现的。
String getMessage (String code
、
Object[] args
、
Locale loc)
:本质上和上一个方法是一样的,除了一点区别:没有默认值可以指定;如果信息找不到,就会抛出一个
NoSuchMessage Exception
。
String getMessage(MessageSourceResolvable resolvable
、
Locale locale)
:上面两个方法使用的所有属性都可以封装到一个叫做
MessageSourceResolvable
的类中,你可以通过这个方法直接使用它。
当
ApplicationContext
被加载的时候,它会自动查找在
context
中定义的
MessageSource bean
,这个
bean
必须叫做
message source
。如果找到了这样的一个
bean
,所有对上述方法的调用将会被委托给找到的
message source
。如果没有找到
message source
,
ApplicationContext
将会尝试查它的父亲是否包含这个名字的
bean
。如果有,它将会把找到的
bean
作为
Message Source
。如果它最终没有找到任何信息源,一个空的
StaticMessageSource
将会被实例化,使它能够接受上述方法的调用。
Spring
目前提供了两个
MessageSource
的实现,它们是
ResourceBundleMessageSource
和
StaticMessageSource
。它们都实现了
NestingMessageSource
,
以便能够嵌套地解析信息。
StaticMessageSource
很少被使用,但是它提供以编程的方式向
source
增加信息。
Resource BundleMessageSource
用得更多一些,我们将提供它的一个例子。
<beans>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundle MessageSource">
<property name="basenames">
<list>
<value>format</value>
<value>exceptions</value>
<value>windows</value>
</list>
</property>
</bean>
</beans>
这段配置假定你在
classpath
有
3
个
resource bundle
,分别叫做
f
format
、
exceptions
和
windows
。
使用
JDK
通过
ResourceBundle
解析信息的标准方式,任何解析信息的请求都会被处理。
(
2
)事件传递
ApplicationContext
中的事件处理是通过
ApplicationEvent
类和
ApplicationListener
接口来提供的。如果上下文中部署了一个实现了
ApplicationListener
接口的
bean
,每次一个
ApplicationEvent
发布到
ApplicationContext
时,那个
bean
就会被通知。实质上,这是标准的
Observer
设计模式。
Spring
提供了
3
个标准事件,如表
6-2
所示。
表
6-2
内置事件
事
件
|
解
释
|
ContextRefreshedEvent
|
当
ApplicationContext
已经初始化或刷新后发送的事件。这里初始化意味着所有的
bean
被装载,
singleton
被预实例化,以及
ApplicationContext
已准备好
|
ContextClosedEvent
|
当使用
ApplicationContext
的
close()
方法结束上下文的时候发送的事件。这里结束意味着:
singleton
被销毁
|
RequestHandledEvent
|
一个与
Web
相关的事件,告诉所有的
bean
一个
HTTP
请求已经被响应了(这个事件将会在一个请求结束后被发送)。注意,这个事件只能应用于使用了
Spring
的
DispatcherServlet
的
Web
应用
|
同样也可以实现自定义的事件。通过调用
ApplicationContext
的
publishEvent()
方法,并且指定一个参数,这个参数是你自定义的事件类的一个实例。我们来看一个例子,首先是
ApplicationContext
。
<bean id="emailer" class="example.EmailBean">
<property name="blackList">
<list>
<value>black@list.org</value>
<value>white@list.org</value>
<value>john@doe.org</value>
</list>
</property>
</bean>
<bean id="blackListListener" class="example.BlackListNotifier">
<property name="notificationAddress">
<value>spam@list.org</value>
</property>
</bean>
然后是实际的bean。
public class EmailBean implements ApplicationContextAware {
/** the blacklist */
private List blackList;
public void setBlackList(List blackList) {
this.blackList = blackList;
}
public void setApplicationContext(ApplicationContext ctx) {
this.ctx = ctx;
}
public void sendEmail(String address, String text) {
if (blackList.contains(address)) {
BlackListEvent evt = new BlackListEvent(address, text);
ctx.publishEvent(evt);
return;
}
// send email
}
}
public class BlackListNotifier implement ApplicationListener {
/** notification address */
private String notificationAddress;
public void setNotificationAddress(String notificationAddress) {
this.notificationAddress = notificationAddress;
}
public void onApplicationEvent(ApplicationEvent evt) {
if (evt instanceof BlackListEvent) {
// notify appropriate person
}
}
}
(
3
)在
Spring
中使用资源
很多应用程序都需要访问资源。
Spring
提供了一个清晰透明的方案,以一种协议无关的方式访问资源。
ApplicationContext
接口包含一个方法(
getResource(String)
)负责这项工作。
Resource
类定义了几个方法,这几个方法被所有的
Resource
实现所共享,资源功能如表
6-3
所示。
表
6-3
资源功能
方
法
|
解
释
|
getInputStream()
|
用
InputStream
打开资源,并返回这个
InputStream
|
exists()
|
检查资源是否存在,如果不存在,返回
false
|
isOpen()
|
如果这个资源不能打开多个流,将会返回
true
。因为除了基于文件的资源,一些资源不能被同时多次读取,它们就会返回
false
|
getDescription()
|
返回资源的描述,通常是全限定文件名或者实际的
URL
|
Spring
提供了几个
Resource
的实现。它们都需要一个
String
表示的资源的实际位置。依据这个
String
,
Spring
将会自动为你选择正确的
Resource
实现。当向
ApplicationContext
请求一个资源时,
Spring
首先检查你指定的资源位置,寻找任何前缀。根据不同的
Application Context
的实现,不同的
Resource
实现可被使用。
Resource
最好是使用
ResourceEditor
来配置,比如
XmlBeanFactory
。
posted on 2006-11-01 10:39
OMG 阅读(717)
评论(0) 编辑 收藏 所属分类:
Spring