OMG,到底在寻找什么..................
(构造一个完美的J2EE系统所需要的完整知识体系)
posts - 198,  comments - 37,  trackbacks - 0

原贴地址: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 阅读(770) 评论(0)  编辑  收藏 所属分类: Spring

<2006年11月>
日一二三四五六
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

常用链接

留言簿(1)

随笔分类

随笔档案

IT风云人物

文档

朋友

相册

经典网站

搜索

  •  

最新评论

阅读排行榜

评论排行榜