目录

beans和bean

beans之唯我独尊

description、import和alias

description

import

alias

bean

id属性

class属性

bean的具体属性及里面的内容

构造方法注入的XML之道

type属性

index属性

setter方法注入的XML之道

property和Constructor-arg中可用的配置项

Value

ref

idref

内部bean

list

Set

map

props

null

depends-on

autowire

no

byName

byType

Constructor

autodetect

手动绑定与自动绑定

dependency-check

lazy-init

bean的继承

bean的scope

singleton

prototype

request、session和global session

自定义scope类型

工厂方法与FactoryBean

静态工厂方法 Static Factory Method)

非静态工厂方法(Instance Factory Method)

FactoryBean

bean的方法替换与prototype得到最新对象

方法注入

使用BeanFactoryAware接口

使用ObjectFactoryCreatingFactoryBean

方法替换


XML格式的容器信息管理方式是Spring提供的最为强大、支待最为全面的方式。从Spring的参考 文档到各Spring相关书籍,都是按照XML的配置进行说明的,这部分内容可以让你充分领略到Spring 的IoC容器的魅力,以致于我们也不得不带你初次或者再次踏上Spring的XML之旅。

beans和bean

所有使用XML文件进行配置信息加载的Spring IoC容器,包括BeanFactory和 ApplicationContext的所有XML相应实现,都使用统一的XML格式。

在Spring 2.0版本之前,这种格 式由Spring提供的DTD规定,也就是说,所有的Spring容器加载的XML配置文件的头部,都需要以下 形式的DOCTYPE声明:

从Spring 2.0版本之后,Spring在继续保持向前兼容的前提下,既可以继续使用DTD方式的DOCTYPE 进行配置文件格式的限定,又引入了基于XML Schema的文档声明。所以,Spring 2.0之后,同样可以 使用代码清单所展示的基于XSD的文档声明。

不过,不管使用哪一种形式的文档声明,实际上限定的元素基本上是相同的。让我们从最顶层的 元素开始,看一下这两种文档声明都限定了哪些元素吧!

所有注册到容器的业务对象,在Spring中称之为Bean。所以,每一个对象在XML中的映射也自然 而然地对应一个叫做<bean>的元素。既然容器最终可以管理所有的业务对象,那么在XML中把这些 叫做<bean>的元素组织起来的,就叫做<beans>。多个<bean>组成一个<beans>很容易理解,不是吗?

beans之唯我独尊

<beans>是XML配置文件中最顶层的元素,它下面可以包含0或者1个<description>和多个 <bean>以及<import>或者<alias>, 如图所示。

<beans>作为所有<bean>的“统帅",它拥有相应的属性(attribute)对所辖的<bean>进行统一 的默认行为设置,包括如下几个。

Default-lazy-init。其值可以指定为true或者false, 默认值为false。用来标志是否对所 有的<bean>进行延迟初始化。

Default-autowire。可以取值为no、byName、byType、Constructor以及autodetect。默 认值为no, 如果使用自动绑定的话,用来标志全体bean使用哪一种默认绑定方式。

Default-dependency-check。可以取值none、objects、simple以及all, 默认值为none, 即不做依赖检查。

Default-init-method。如果所管辖的<bean>按照某种规则,都有同样名称的初始化方法的 话,可以在这里统一指定这个初始化方法名,而不用在每一个<bean>上都重复单独指定。

Default-destiroy-method。与Default-init-method相对应,如果所管辖的bean有按照某种 规则使用了相同名称的对象销毁方法,可以通过这个属性统一指定。

description、import和alias

之所以把这几个元素放到一起讲解,是因为通常情况下它们不是必需的。不过,了解一下也没什 么不好,不是吗?

description

可以通过<description>在配置的文件中指定一些描述性的信息。通常情况下,该元素是省略的。

当然,如果愿意,<description>随时可以为我们效劳。

import

通常情况下,可以根据模块功能或者层次关系,将配置信息分门别类地放到多个配置文件中。在 想加载主要配置文件,并将主要配置文件所依赖的配置文件同时加载时,可以在这个主要的配置文件 中通过<import>元素对其所依赖的配置文件进行引用。比如,如果A.xml中的<bean:>定义可能依赖 B.xml中的某些<bean>定义,那么就可以在A.xml中使用<import>将B.xml引入到A.xml, 以类似于 <import resource="B.xml"户的形式。

但是,这个功能在我看来价值不大,因为容器实际上可以同时加载多个配置,没有必要非通过一 个配置文件来加载所有配置。不过,或许在有些场景中使用这种方式比较方便也说不定。

alias

可以通过<alias>为某些<bean>起一些“外号” (别名),通常情况下是为了减少输入。比如, 假设有个<bean>, 它的名称为dataSourceForMasterDatabase, 你可以为其添加一个<alias>, 像这样 <alias name="dataSourceForMasterDatabase" alias="masterDataSource"/>。以后通过 dataSourceForMasterDatabase或者masterDataSource来引用这个<bean>都可以,只要你觉得方便 就行。

bean

哦,错了,是孤孤单单一个Bean。每个业务对象作为个体,在Spring的XML配置文件中是与<bean> 元素一一对应的。窥一斑而知全豹,只要我们了解单个的业务对象是如何配置的,剩下的就可以“依 葫芦画飘”了。所以,让我们先从最简单的单一对象配置开始吧!如下代码演示了最基础的对象配置 形式:

<bean id="djNewsListener" class=" .. impl.DowJonesNewsListener"> </bean>

id属性

通常,每个注册到容器的对象都需要一个唯一标志来将其与“同处一室”的"兄弟们“区分开来, 就好像我们每一个人都有一个身份证号一样(重号的话就比较麻烦)。通过过属性来指定当前注册对 象的beanName是什么。这里,通过指定beanName为djNewsListener。实际上,并非任何情况下都 需要指定每个<bean>的id,有些情况下,id可以省略,比如后面会提到的内部<bean>以及不需要根据 beanName明确依赖关系的场合等。

除了可以使用id来指定<bean>在容器中的标志,还可以使用name属性来指定<bean>的别名 (alias)。比如,以上定义,我们还可以像如下代码这样,为其添加别名:

<bean id="djNewsListener"  name="/news/djNewsListener,dowJonesNewsListener" class=" .. impl.DowJonesNewsListener">

</bean>

与id属性相比,name属性的灵活之处在于,name可以使用id不能使用的一些字符,比如/。而且 还可以通过逗号、空格或者冒号分割指定多个name。

name的作用跟使用<alias>为id指定多个别名基 本相同:

<alias name="djNewsListener" alias="/news/ctjNewsListener"/> <alias name="ctjNewsListener" alias="ctowJonesNewsListener"/>

class属性

每个注册到容器的对象都需要通过<bean>元素的class属性指定其类型,否则,容器可不知道这 个对象到底是何方神圣。在大部分情况下,该属性是必须的。仅在少数情况下不需要指定,如后面将 提到的在使用抽象配置模板的情况下。

bean的具体属性及里面的内容

在大部分情况下,你不太可能选择单独”作战”,业务对象也是;各个业务对象之间会相互协作 来更好地完成同一使命。这时,各个业务对象之间的相互依赖就是无法避免的。对象之间需要相互协 作,在横向上它们存在一定的依赖性。而现在我们就是要看一下,在Spring的IoC容器的XML配置中, 应该如何表达这种依赖性。

既然业务对象现在都符合IoC的规则,那么要了解的表达方式其实也很简单,无非就是看一下构 造方法注入和setter方法注入通过XML是如何表达的而已。那么,让我们开始吧!

构造方法注入的XML之道

按照Spring的IoC容器配置格式,要通过构造方法注入方式,为当前业务对象注入其所依赖的对象, 需要使用<Constuctor-arg>。正常情况下,如以下代码所示:

对于<ref>元素,稍后会进行详细说明。这里你只需要知道,通过这个元素来指明容器将为 djNewsProvider这个<bean>注入通过<ref>所引用的Bean实例。这种方式可能看起来或者编写起来 不是很简洁,最新版本的Spring也支持配置简写形式,如以下代码所示:

简洁多了不是嘛?其实,无非就是表达方式不同而已,实际达到的效果是一样的。

有些时候,容器在加载XML配置的时候,因为某些原因,无法明确配置项与对象的构造方法参数 列表的一一对应关系,就需要请<constructor-arg>的type或者index属性出马。比如,对象存在多 个构造方法,当参数列表数目相同而类型不同的时候,容器无法区分应该使用哪个构造方法来实例化 对象,或者构造方法可能同时传入最少两个类型相同的对象

type属性

假设有一个对象定义如代码清单

该类声明了两个构造方法,分别都只是传入一个参数,且参数类型不同。这时,我们可以进行配 置,如以下代码所示:

如果从BeanFactory取得该对象并调用toString()查看的话,我们会发现Spring调用的是第一个 构造方法,因为输出是如下内容:

但是,如果我们想调用的却是第二个传入int类型参数的构造方法,又该如何呢?可以使用type属 性,通过指定构造方法的参数类型来解决这一问题,配置内容如下代码所示:

index属性

当某个业务对象的构造方法同时传入了多个类型相同的参数时,Spring又该如何将这些配置中的 信息与实际对象的参数一一对应呢?好在,如果配置项信息和对象参数可以按照顺序初步对应的话,Spring还是可以正常工作的

但是,如果要让"11111"作为对象的第二个参数,而将"22222"作为第一个参数来构造对象, 又该如何呢?好!可以颠倒配置项

setter方法注入的XML之道

与构造方法注入可以使用<Constructor-arg>注入配置相对应,Spring为setter方法注入提供了 <property>元素。

<property>有一个name属性(attribute) , 用来指定该<property>将会注入的对象所对应的实例变量名称。之后通过value或者ref属性或者内嵌的其他元素来指定具体的依赖对象引用或者值,如以 下代码所示:

当然,如果只是使用<property>进行依赖注入的话,请确保你的对象提供了默认的构造方法, 也就是一个参数都没有的那个。

以上配置形式还可以简化为如下形式:

使用<property>的setter方法注入和使用<Constructor-arg>的构造方法注入并不是水火不容 的。实际上,如果需要,可以同时使用这两个元素:

当然,现在需要MockBusinessObject提供一个只有一个String类型参数的构造方法,并且为 dependency2提供了相应的setter方法。代码清单演示了符合条件的一个业务对象定义。

property和Constructor-arg中可用的配置项

之前我们看到,可以通过在<property>和<Constructor-arg>这两个元素内部嵌套<Value>或者 <ref>, 来指定将为当前对象注入的简单数据类型或者某个对象的引用。不过,为了能够指定多种注 入类型,Spring还提供了其他的元素供我们使用,这包括bean、ref、idref、value、null、list、set、map、 props。下面我们来逐个详细讲述它们。

提示 以下涉及的所有内嵌元素,对于<property>和<constructor-arg>都是通用的。

Value

可以通过value为主体对象注入简单的数据类型,不但可以指定String类型的数据, 而且可以指定其他Java语言中的原始类型以及它们的包装器(wrapper)类型,比如int,integer等。 容器在注入的时候,会做适当的转换工作(我们会在后面揭示转换的奥秘)。你之前已经见过如何使 用<value>了,不过让我们通过如下代码来重新认识一下它:

当然,如果愿意,你也可以使用如下的简化形式(不过这里的value是以上一层元素的属性身份 出现):

需要说明的是,<value>是最“底层”的元素,它内部不能再嵌套使用其他元素了。

ref

使用ref来引用容器中其他的对象实例,可以通过ref的local、parent和bean属性来 指定引用的对象的beanName是什么。代码清单演示了ref及其三个对应属性的使用情况。

local、parent和bean的区别在于:

local只能指定与当前配置的对象在同一个配置文件的对象定义的名称(可以获得XML解析器 的过约束验证支持);

parent则只能指定位于当前容器的父容器中定义的对象引用;

注意 Beanfactory可以分层次(通过实现HierarchicalBeanfactory接口),容器A在初始 化的时候,可以首先加载容器B中的所有对象定义,然后再加载自身的对象定义,这样,容器 B就成为了容器A的父容器,容器A可以引用容器B中的所有对象定义

childContainer中定义的对象,如果通过parent指定依赖,则只能引用parentContainer中 的对象定义。

bean则基本上通吃,所以,通常情况下,直接使用bean来指定对象引用就可以了。

<ref>的定义为<!ELEMENT ref EMPTY>, 也就是说,它下面没有其他子元素可用了,别硬往人家 肚子里塞东西哦。

idref

如果要为当前对象注入所依赖的对象的名称,而不是引用,那么通常情况下,可以 使用<value>来达到这个目的,使用如下形式:

但这种场合下,使用过idef才是最为合适的。因为使用idref, 容器在解析配置的时候就可以帮 你检查这个beanName到底是否存在,而不用等到运行时才发现这个beanName对应的对象实例不存在。 毕竟,输错名字的问题很常见。以下代码演示了idref的使用:

这段配置跟上面使用<Value>达到了相同的目的,不过更加保险。如果愿意,也可以通过local而 不是bean来指定最终值,不过,bean比较大众化哦。

内部bean

使用<ref>可以引用容器中独立定义的对象定义。但有时,可能我们所依赖的对 象只有当前一个对象引用,或者某个对象定义我们不想其他对象通过<ref>引用到它。这时,我们可 以使用内嵌的<bean>, 将这个私有的对象定义仅局限在当前对象。对于FX新闻系统的DowJonesNews­Listener而言,实际上只有道琼斯的FXNewsProvider会使用它。而且,我们也不想让其他对象引用 到它。为此完全可以像代码清单这样,将它配置为内部<bean>的形式。

这样,该对象实例就只有当前的djNewsProvider可以使用,其他对象无法取得该对象的引用。

注意 因为就只有当前对象引用内部<bean>所指定的对象,所以,内部<bean>的id不是必须 的。当然,如果你愿意指定过,那也是无所谓的。如下所示:

内部<bean>的配置只是在位置上有所差异,但配置项上与其他的<bean>是没有任何差别的。也 就是说,<bean>内嵌的所有元素,内部<bean>的<bean>同样可以使用。如果内部<bean>对应的对象 还依赖于其他对象,你完全可以像其他独立的<bean>定义一样为其配置相关依赖,没有任何差别。

list

<list>对应注入对象类型为java.util .List及其子类或者数组类型的依赖对象。

通过<list>可以有序地为当前对象注入以collection形式声明的依赖。代码清单给出了一个使用 <list>的实例演示。

注意,<list>元素内部可以嵌套其他元素,并且可以像paraml所展示的那样夹杂配置。但是,从 好的编程实践来说,这样的处理并不恰当,除非你真的知道自己在做什么! (以上只是出于演示的目 的才会如此配置)。

Set

如果说<list>可以帮你有序地注入一系列依赖的话,那么<Set>就是无序的,而且, 对于set来说,元素的顺序本来就是无关紧要的。<Set>对应注入Java Collection中类型为java.util. Set或者其子类的依赖对象。代码清单演示了通常情况下<Set>的使用场景。

例子就是例子,只是为了给你演示这个元素到底有多少能耐。从配置上来说,这样多层嵌套、多元素混杂配置是完全没有问题的。不过,各位在具体编程实践的时候可要小心了。如果你真的想这么 夹杂配置的话,不好意思,估计ClassCastException会很愿意来亲近你,而这跟容器或者配置一点 儿关系也没有。

map

与列表(list)使用数字下标来标识元素不同,映射(map)可以通过指定的键(key) 来获取相应的值。如果说在<list>中混杂不同元素不是一个好的实践(方式)的话,你就应该求助 <map>。

<map>与<list>和<Set>的相同点在于,都是为主体对象注入Collection类型的依赖,不同点 在于它对应注入java.util.Map或者其子类类型的依赖对象。代码清单演示了<map>的通常使用 场景。

对于<map>来说,它可以内嵌任意多个<entry>, 每一个<entry>都需要为其指定一个键和一个值, 就跟真正的java.util.Map所要求的一样。

指定entry的键。可以使用<entry>的属性key或者key-ref来指定键,也可以使用<entry> 的内嵌元素<key>来指定键,这完全看个人喜好,但两种方式可以达到相同的效果。在<key>内 部,可以使用以上提到的任何元素来指定键,从简单的<value>到复杂的Collection, 只要映射 需要,你可以任意发挥。

指定entry对应的值。<entry>内部可以使用的元素,除了<key>是用来指定键的,其他元素 可以任意使用,来指定entry对应的值。除了之前提到的那些元素,还包括马上就要谈到的 <props>。如果对应的值只是简单的原始类型或者单一的对象引用,也可以直接使用<entry> 的value或者value-ref这两个属性来指定,从而省却多敲入几个字符的工作量。

注意 key属性用于指定通常的简单类型的键,而key-ref则用于指定对象的引用作为键。

所以,如果你不想敲那么些字符,可以像代码清单所展示的那样使用<map>进行依赖注入的配置。

props

<props>是简化后了的<map>, 或者说是特殊化的map, 该元素对应配置类型为 java.util.Properties的对象依赖。因为Properties只能指定string类型的键(key)和值,所以, <props>的配置简化很多,只有固定的格式,见代码清单。

每个<props>可以嵌套多个<prop>, 每个<prop>通过其key属性来指定键,在<prop>内部直接指 定其所对应的值。<prop>内部没有任何元素可以使用,只能指定字符串,这个是由java.util. Properties的语意决定的。

null

最后一个提到的元素是<null/>, 这是最简单的一个元素,因为它只是一个空元素, 而且通常使用到它的场景也不是很多。

对于String类型来说,如果通过value以这样的方式指定注入, 即<value></value>, 那么,得到的结果是"", 而不是null。所以,如果需要为这个string对应的值 注入null的话,请使用<null/>。当然,这并非仅限于string类型,如果某个对象也有类似需求,请 不要犹豫。代码清单演示了一个使用<null/>的简单场景。

depends-on

通常情况下,可以直接通过之前提到的所有元素,来显式地指定bean之间的依赖关系。这样,容 器在初始化当前bean定义的时候,会根据这些元素所标记的依赖关系,首先实例化当前bean定义所依 赖的其他bean定义。但是,如果某些时候,我们没有通过类似<ref>的元素明确指定对象A依赖于对象 B的话,如何让容器在实例化对象A之前首先实例化对象B呢?

系统中所有需要日志记录的类,都需要在这些类使用之前首先初始化log4j。那么,就会非显式地 依赖于SystemConfigurationSetup的静态初始化块。如果ClassA需要使用log4j, 那么就必须在bean 定义中使用depends-on来要求容器在初始化自身实例之前首先实例化SystemConfigurationSetup, 以保证日志系统的可用,如下代码演示的正是这种情况:

举log4j在静态代码块(static block)中初始化的例子在实际系统中其实不是很合适,因为通常在 应用程序的主入口类初始化日志就可以了。这里主要是给出depends-on可能的使用场景,大部分情 况下,是那些拥有静态代码块初始化代码或者数据库驱动注册之类的场景。

如果说ClassA拥有多个类似的非显式依赖关系,那么,你可以在ClassA的depends-on中通过逗号 分割各个beanName, 如下代码所示:

autowire

除了可以通过配置明确指定bean之间的依赖关系,Spirng还提供了根据bean定义的某些特点将相 互依赖的某些bean直接自动绑定的功能。通过<bean>的autowire属性,可以指定当前bean定义采用某 种类型的自动绑定模式。这样,你就无需手工明确指定该bean定义相关的依赖关系,从而也可以免去 一些手工输入的工作量。

Spring提供了5种自动绑定模式,即no、byName、byType、constructor和autodetect,下面是 它们的具体介绍。

no

容器默认的自动绑定模式,也就是不采用任何形式的自动绑定,完全依赖手工明确配置各个bean 之间的依赖关系,以下代码演示的两种配置是等效的:

byName

按照类中声明的实例变量的名称,与XML配置文件中声明的bean定义的beanName的值进行匹配, 相匹配的bean定义将被自动绑定到当前实例变量上。这种方式对类定义和配置的bean定义有一定的限 制。假设我们有如下所示的类定义:

需要注意两点:第一,我们并没有明确指定fooBean的依赖关系,而仅指定了它的autowire属性 为byName; 第二,第二个bean定义的过为emphasisAttribute, 与Foo类中的实例变量名称相同。

byType

如果指定当前bean定义的autowire模式为byType, 那么,容器会根据当前bean定义类型,分析其 相应的依赖对象类型,然后到容器所管理的所有bean定义中寻找与依赖对象类型相同的bean定义,然后将找到的符合条件的bean自动绑定到当前bean定义。

对于byName模式中的实例类Foo来说,容器会在其所管理的所有bean定义中寻找类型为Bar的bean 定义。如果找到,则将找到的bean绑定到Foo的bean定义;如果没有找到,则不做设置。但如果找到 多个,容器会告诉你它解决不了"该选用哪一个"的问题,你只好自己查找原因,并自己修正该问题。 所以,byType只能保证,在容器中只存在一个符合条件的依赖对象的时候才会发挥最大的作用,如果 容器中存在多个相同类型的bean定义,那么,不好意思,采用手动明确配置吧!

指定byType类型的autowire模式与byName没什么差别,只是autowire的值换成byType而已,可 以参考如下代码

Constructor

byName和byType类型的自动绑定模式是针对property的自动绑定,而Constructor类型则是针对 构造方法参数的类型而进行的自动绑定,它同样是byType类型的绑定模式。不过,Constructor是匹 配构造方法的参数类型,而不是实例属性的类型。与byType模式类似,如果找到不止一个符合条件的 bean定义,那么,容器会返回错误。使用上也与byType没有太大差别,只不过是应用到需要使用构造 方法注入的bean定义之上,代码清单给出了一个使用construtor模式进行自动绑定的简单场景演 刀。

autodetect

这种模式是byType和constructor模式的结合体,如果对象拥有默认无参数的构造方法,容器会 优先考虑byType的自动绑定模式。否则,会使用constructor模式。当然,如果通过构造方法注入绑 定后还有其他属性没有绑定,容器也会使用byType对剩余的对象属性进行自动绑定。

手动绑定与自动绑定

手工明确指定的绑定关系总会覆盖自动绑定模式的行为。

自动绑定只应用于“原生类型、String类型以及Classes类型以外”的对象类型,对 “原生类型、String类型和Classes类型”以及“这些类型的数组”应用自动绑定是无效的。

自动绑定和手动明确绑定各有利弊。自动绑定的优点有如下两点。

(1)某种程度上可以有效减少手动敲入配置信息的工作量。

(2)某些情况下,即使为当前对象增加了新的依赖关系,但只要容器中存在相应的依赖对 象,就不需要更改任何配置信息。

自动绑定的缺点有如下几点。

(1)自动绑定不如明确依赖关系一目了然。我们可以根据明确的依赖关系对整个系统有一 个明确的认识,但使用自动绑定的话,就可能需要在类定义以及配置文件之间,甚至各个配置 文件之间来回转换以取得相应的信息。

(2)某些情况下,自动绑定无法满足系统需要,甚至导致系统行力异常或者不可预知。根 据类型(byType)匹配进行的自动绑定,如果系统中增加了另一个相同类型的bean定义,那么 整个系统就会崩溃;根据名字(byName)匹配进行的自动绑定,如果把原来系统中相同名称的 bean定义类型给换掉,就会造成问题,而这些可能都是在不经意间发生的。

(3)使用自动绑定,我们可能无法荻得某些工具的良好支持,比如Srring IDE。

通常情况下,只要有良好的XML编辑器支待,我不会介意多敲那几个字符。起码自己可以对整个 系统的行为有完全的把握。当然,任何事物都不绝对,只要根据相应场景找到合适的就可以。

噢,对了,差点儿忘了!作为所有<bean>的统帅,<beans>有—个Default-autowire属性,它 可以帮我们省去为多个<bean>单独设置autowire属性的麻烦,Default-autowire的默认值为no, 即 不进行自动绑定。如果想让系统中所有的心ean>定义都使用byType模式的自动绑定,我们可以使用 如下配置内容:

dependency-check

我们可以使用每个<bean>的dependency-check属性对其所依赖的对象进行最终检查,就好像电影 里每队美国大兵上战场之前,带队的军官都会朝着士兵大喊“检查装备,check, recheck"是一个道理。 该功能主要与自动绑定结合使用,可以保证当自动绑定完成后,最终确认每个对象所依赖的对象是否按 照所预期的那样被注入。当然,并不是说不可以与平常的明确绑定方式一起使用。

该功能可以帮我们检查每个对象某种类型的所有依赖是否全部已经注入完成,不过可能无法细化 到具体的类型检查。但某些时候,使用setter方法注入就是为了拥有某种可以设置也可以不设置的灵活 性,所以,这种依赖检查并非十分有用,尤其是在手动明确绑定依赖关系的情况下。

与军官会让大兵检查枪支弹药和防弹衣等不同装备—样,可以通过dependency-check指定容器 帮我们检查某种类型的依赖,基本上有如下4种类型的依赖检查。

none。不做依赖检查。将dependency-check指定为none跟不指定这个属性等效,所以,还是 不要多敲那几个字符了吧。默认情况下,容器以此为默认值。

simple。如果将dependency-check的值指定为simple, 那么容器会对简单属性类型以及相 关的collection进行依赖检查,对象引用类型的依赖除外。

object。只对对象引用类型依赖进行检查。

all。将simple和object相结合,也就是说会对简单属性类型以及相应的collection和所有对 象引用类型的依赖进行检查。

总地来说,控制得力的话,这个依赖检查的功能我们基本可以不考虑使用。

lazy-init

延迟初始化(lazy-init)这个特性的作用,主要是可以针对ApplicationContext容器的bean 初始化行为施以更多控制。与Beanfactory不同,ApplicationContext在容器启动的时候,就会马 上对所有的"singleton的bean定义进行实例化操作。通常这种默认行为是好的,因为如果系统有问 题的话,可以在第一时间发现这些问题,但有时,我们不想某些bean定义在容器启动后就直接实例化, 可能出于容器启动时间的考虑,也可能出于其他原因的考虑。总之,我们想改变某个或者某些bean定 义在ApplicationContext容器中的默认实例化时机。这时,就可以通过<bean>的lazy-init属性来 控制这种初始化行为,如下代码所示:

这样,ApplicationContext容器在启动的时候,只会默认实例化not-lazy-init-bean而不会实 例化lazy-init-bean。

当然,仅指定lazy-init-bean的lazy-init为true, 并不意味着容器就一定会延迟初始化该bean 的实例。如果某个非延迟初始化的bean定义依赖于lazy-init-bean, 那么毫无疑问,按照依赖决计 的顺序,容器还是会首先实例化lazy-init-bean, 然后再实例化后者,如下代码演示了这种相互牵 连导致延迟初始化失败的情况:

虽然lazy-init-bean是延迟初始化的,但因为依赖它的not-lazy-init-bean并不是延迟初始 化,所以lazy-init-bean还是会被提前初始化,延迟初始化的良好打算"泡汤”。如果我们真想保 证lazy-init-bean一定会被延迟初始化的话,就需要保证依赖于该bean定义的其他bean定义也同样设 置为延迟初始化。在bean定义很多时,好像工作量也不小哦。不过不要忘了,<beans>可是所有<bean> 的统领啊,让它一声令下吧!如代码清单所演示的,在顶层由<beans>统一控制延迟初始化行为 即可

bean的继承

除了单独存在的bean以及多个bean之间的横向依赖关系,我们也不能忽略“纵向上“各个bean之 间的关系。确切来讲,我其实是想说“类之间的继承关系”。不可否认,继承可是在面向对象界声名 远扬啊。

假设我们某一天真的需要对FXNewsProvider使用继承进行扩展,那么可能会声明如下代码所示 的子类定义:

实际上,我们想让该子类与FXNewsProvider使用相同的IFXNewsPersister, 即DowJonesNews­Persister, 那么可以使用如代码清单所示的配置。

但实际上,这种配置存在冗余,而且也没有表现两者之间的纵向关系。所以,我们可以引入XML 中的bean的“继承“配置,见代码清单

我们在声明subNewsProvider的时候,使用了parent属性,将其值指定为superNewsProvider, 这样就继承了superNewsProvider定义的默认值,只需要将特定的属性进行更改,而不要全部又重新 定义一遍。

parent属性还可以与abstract属性结合使用,达到将相应bean定义模板化的目的。比如,我们还 可以像代码清单所演示的这样声明以上类定义。

newsProviderTemplate的bean定义通过abstract属性声明为true, 说明这个bean定义不需要实 例化。实际上,这就是之前提到的可以不指定class属性的少数场景之一(当然,同时指定class和 abstract=“true"也是可以的)。该bean定义只是—个配置模板,不对应任何对象。superNews­Provider和subNewsProvider通过parent指向这个模板定义,就拥有了该模板定义的所有属性配置。 当多个bean定义拥有多个相同默认属性配置的时候,你会发现这种方式可以带来很大的便利。

另外,既然这里提到abstract,对它就多说几句。容器在初始化对象实例的时候,不会关注将 abstract属性声明为true的bean定义。如果你不想容器在初始化的时候实例化某些对象,那么可以将 其abstract属性赋值true, 以避免容器将其实例化。对于ApplicationContext容器尤其如此,因为 默认情况下,ApplicationContext会在容器启动的时候就对其管理的所有bean进行实例化,只有标 志为abstract的bean除外。

bean的scope

BeanFactory除了拥有作为IoC Service Provider的职责,作为一个轻量级容器,它还有着其他一些 职责,其中就包括对象的生命周期管理。

scope用来声明容器中的对象所应该处的限定场景或者说该对象的存活时间,即容器在对象进入其 相应的scope之前,生成并装配这些对象,在该对象不再处于这些scope的限定之后,容器通常会销毁这些对象。打个比方吧!我们都是处于社会(容器)中,如果把中学教师作为一个类定义,那么当容 器初始化这些类之后,中学教师只能局限在中学这样的场景中;中学,就可以看作中学教师的scope。

Spring容器最初提供了两种bean的scope类型: singleton和prototype, 但发布2.0之后,又引入了另 外三种scope类型,即request、session和global session类型。不过这三种类型有所限制,只能在Web应 用中使用。也就是说,只有在支持\Veb应用的ApplicationContext中使用这三个scope才是合理的。

我们可以通过使用<bean>的singleton或者scope属性来指定相应对象的scope, 其中,scope属性只 能在XSD格式的文档声明中使用,类似于如下代码所演示的形式:

让我们来看一下容器提供的这几个scope是如何限定相应对象的吧!

singleton

配置中的bean定义可以看作是一个模板,容器会根据这个模板来构造对象。但是要根据这个模板 构造多少对象实例,又该让这些构造完的对象实例存活多久,则由容器根据bean定义的scope语意来决 定。标记为拥有singleton scope的对象定义,在Spring的IoC容器中只存在一个实例,所有对该对象的引 用将共享这个实例。该实例从容器启动,并因为第一次被请求而初始化之后,将一直存活到容器退出, 也就是说,它与IoC容器”几乎“拥有相同的“寿命”。

图是Spring参考文档中所给出的singleton的bean的实例化和注入语意演示图例,或许可以更形 象地说明问题。

需要注意的一点是,不要因为名字的原因而与GoF所提出的Singleton模式相混淆,二者的语意是 不同的:标记为singleton的bean是由容器来保证这种类型的bean在同一个容器中只存在一个共享实例; 而Singleton模式则是保证在同一个Class loader中只存在一个这种类型的实例。

可以从两个方面来看待singleton的bean所具有的特性。

对象实例数量。singleton类型的bean定义,在一个容器中只存在一个共享实例,所有对该类型bean的依赖都引用这一单一实例。这就好像每个幼儿园都会有一个滑梯一样,这个幼儿园的小 朋友共同使用这一个滑梯。而对于该幼儿园容器来说,滑梯实际上就是一个singleton的bean。

对象存活时间。singleton类型bean定义,从容器启动,到它第一次被请求而实例化开始,只要 容器不销毁或者退出,该类型bean的单一实例就会一直存活。

通常情况下,如果你不指定bean的scope, singleton便是容器默认的scope, 所以,下面三种配置形 式实际上达成的是同样的效果:

prototype

针对声明为拥有prototype scope的bean定义,容器在接到该类型对象的请求的时候,会每次都重新 生成一个新的对象实例给请求方。虽然这种类型的对象的实例化以及属性设置等工作都是由容器负责 的,但是只要准备完毕,并且对象实例返回给请求方之后,容器就不再拥有当前返回对象的引用,请 求方需要自己负责当前返回对象的后继生命周期的管理工作,包括该对象的销毁。也就是说,容器每 次返回给请求方一个新的对象实例之后,就任由这个对象实例“自生自灭”了。

让我们继续幼儿园的比喻,看看prototype在这里应该映射到哪些事物。儿歌里好像有旬“排排坐, 分果果”,我们今天要分苹果咯!将苹果的bean定义的scope声明为prototype, 在每个小朋友领取苹果 的时候,我们都是分发一个新的苹果给他。发完之后,小朋友爱怎么吃怎么吃,爱什么时候吃什么时 候吃。但是,吃完后要记得把果核扔到果皮箱哦!而如果你把苹果的bean定义的scope声明为singleton 会是什么情况呢?如果第—个小朋友比较谦让,那么他可能对这个苹果只咬一口,但是下一个小朋友 吃多少就不知道了。当吃得只剩—个果核的时候,下—个来吃苹果的小朋友肯定要哭鼻了的。

所以,对于那些请求方不能共享使用的对象类型,应该将其bean定义的scope设詈为prototype。这 样,每个请求方可以得到自己对应的一个对象实例,而不会出现上面"哭鼻子"的现象。通常,声明 为prototype的scope的bean定义类型,都是—些有状态的,比如保存每个顾客信息的对象。

从Spring参考文档上的这幅图片, 你可以再次了解一下拥有prototype scope的bean定 义,在实例化对象并注入依赖的时候,它的具体语意是个什么样子。

你用以下形式来指定某个bean定义的scope为prototype类型,效果是一样的:

request、session和global session

这三个scope类型是Spimg 2.0之后新增加的,它们不像之前的singleton和prototype那么“通用" , 因为它们只适用于Web应用程序,通常是与XmlWebApplicationContext共同使用。不过,既然它们也属于scope的概念,这里就简单提几旬。

注意 只能使用scope属性才能指定这三种"bean的scope类型”。也就是说,你不得不使用基 于XSD文档声明的XML配置文件格式。

request

request通常的配置形式如下:

Spring容器,即XmlWebApplicationContext会为每个HTTP请求创建一个全新的Request- Processor对象供当前请求使用,当请求结束后,该对象实例的生命周期即告结束。当同时有10个HTTIP请求进来的时候,容器会分别针对这10个请求返回10个全新的Request Processor对象实例,且它们 之间互不干扰。从不是很严格的意义上说,request可以看作prototype的一种特例,除了场景更加具体 之外,语意上差不多。

session

对于Web应用来说,放到session中的最普遍的信息就是用户的登录信息,对于这种放到session中 的信息,我们可使用如下形式指定其scope为session:

Spring容器会为每个独立的session创建属于它们自己的全新的UserPreferences对象实例。与 request相比,除了拥有session scope的bean的实例具有比request scope的bean可能更长的存活时间,其 他方面真是没什么差别。

global session

还是userPreferences, 不过scope对应的值换一下,如下所示:

global session只有应用在基于portlet的Web应用程序中才有意义,它映射到portlet的global范围的 session。如果在普通的基于servlet的Web应用中使用了这个类型的scope, 容器会将其作为普通的session 类型的scope对待。

自定义scope类型

在Spring 2.0之后的版本中,容器提供了对scope的扩展点,这样,你可以根据自己的需要或者应 用的场景,来添加自定义的scope类型。需要说明的是,默认的singleton和prototype是硬编码到代码中 的,而request、session和global session, 包括自定义scope类型,则属于可扩展的scope行列,它们都实 现了org.springframework.beans.Factory.config.Scope接口,该接口定义如下:

要实现自己的scope类型,首先需要给出一个Scope接口的实现类,接口定义中的4个方法并非都 是必须的,但get和remove方法必须实现。我们可以看一下http://www.jroller.com/eu/entry/implementing _efficinet—id _generator中提到的一个ThreadScope的实现

有了Scope的实现类之后,我们需要把这个Scope注册到容器中,才能供相应的bean定义使用。通 常情况下,我们可以使用ConfigurableBeanFactory的以下方法注册自定义scope:

void registerScope(String scopeName, Scope scope);

其中,参数scopeName就是使用的bean定义可以指定的名称,比如Spring框架默认提供的自定义scope 类型reguest或者session。参数Scope即我们提供的Scope实现类实例。

对于以上的ThreadScope, 如果容器为BeanFactory类型(当然,更应该实现Configurable- BeanFactory) , 我们可以通过如下方式来注册该Scope:

之后,我们就可以在需要的bean定义中直接通过“thread"名称来指定该bean定义对应的scope 为以上注册的ThreadScope了,如以下代码所示:

<bean id="beanName" class=" ... " scope="thread" />

除了直接编码调用ConfigurationBeanFactory的registerScope来注册scope, Spring还提供了 一个专门用于统一注册自定义scope的BeanFactoryPostProcessor实现(有关BeanFactoryPost- Processor的更多细节稍后将详述),即org.springframework.beans.Factory.config.Custom­ScopeConfigurer。对于ApplicationContext来说,因为它可以自动识别并加载BeanFactoryPost- Processor, 所以我们就可以直接在配置文件中,通过这个CustomScopeConfigurer注册来Thread­Scope (如代码清单所示)。

在以上工作全部完成之后,我们就可以在自己的bean定义中使用这个新增加到容器的自定义scope thread"了,如下代码演示了通常情况下"thread"自定义scope的使用:

工厂方法与FactoryBean

在强调“面向接口编程”的同时,有一点需要注意:虽然对象可以通过声明接口来避免对特定接 口实现类的过度耦合,但总归需要一种方式将声明依赖接口的对象与接口实现类关联起来。否则,只 依赖一个不做任何事情的接口是没有任何用处的。假设我们有一个像代码清单所声明的Foo类, 它声明了一个BarInterface依赖。

如果该类是由我们设计并开发的,那么还好说,我们可以通过依赖注入,让容器帮助我们解除接 口与实现类之间的耦合性。但是,有时,我们需要依赖第三方库,需要实例化并使用第三方库中的相 关类,这时,接口与实现类的耦合性需要其他方式来避免。

通常的做法是通过使用工厂方法(Factory Method)模式,提供一个工厂类来实例化具体的接口 实现类,这样,主体对象只需要依赖工厂类,具体使用的实现类有变更的话,只是变更工厂类,而主 体对象不需要做任何变动。代码清单演示了这种做法。

针对使用工厂方法模式实例化对象的方式,Spring的IoC容器同样提供了对应的集成支持。我们所 要做的,只是将工厂类所返回的具体的接口实现类注入给主体对象(这里是Foo)。

静态工厂方法 Static Factory Method)

假设某个第三方库发布了Barinterface, 为了向使用该接口的客户端对象屏蔽以后可能对 Barinterface实现类的变动,同时还提供了一个静态的工厂方法实现类staticBarinterface­Factory, 代码如下:

为了将该静态工厂方法类返回的实现注入Foo, 我们使用以下方式进行配置(通过setter方法注入 方式为Foo注入Barinterface的实例):

class指定静态方法工厂类,Factory-method指定工厂方法名称,然后,容器调用该静态方法工 厂类的指定工厂方法(getlnstance) , 并返回方法调用后的结果,即BarlnterfaceImpl的实例。 也就是说,为foo注入的bar实际上是BarlnterfaceImpl的实例,即方法调用后的结果,而不是静态 工厂方法类(StaticBarinterfaceFactory)。我们可以实现自己的静态工厂方法类返回任意类型 的对象实例,但工厂方法类的类型与工厂方法返回的类型没有必然的相同关系。

某些时候,有的工厂类的工厂方法可能需要参数来返回相应实例,而不一定非要像我们的 getInstance()这样没有任何参数。对于这种情况,可以通过<Constructor-arg>来指定工厂方法需 要的参数,比如现在StaticBarinterfaceFactory需要其他依赖来返回某个Barinterface的实现, 其定义可能如下:

为了让包含方法参数的工厂方法能够预期返回相应的实现类实例,我们可以像代码清单所演 示的那样,通过<Constructor-arg>为工厂方法传入相应参数。

唯一需要注意的就是,针对静态工厂方法实现类的bean定义,使用<Constructor-arg>传入的是 工厂方法的参数,而不是静态工厂方法实现类的构造方法的参数。 (况且,静态工厂方法实现类也没 有提供显式的构造方法。

非静态工厂方法(Instance Factory Method)

既然可以将静态工厂方法实现类的工厂方法调用结果作为bean注册到容器中,我们同样可以针对 基于工厂类实例的工厂方法调用结果应用相同的功能,只不过,表达方式可能需要稍微变一下。

现在为Barinterface提供非静态的工厂方法实现类,该类定义如下代码所示:

因为工厂方法为非静态的,我们只能通过某个NonStaticBarInterfaceFactory实例来调用该方 法(哦,错了,是容器来调用),那么也就有了如下的配置内容:

NonStaticBarInterfaceFactory是作为正常的bean注册到容器的,而bar的定义则与静态工厂方 法的定义有些不同。现在使用Factory-bean属性来指定工厂方法所在的工厂类实例,而不是通过 class属性来指定工厂方法所在类的类型。指定工厂方法名则相同,都是通过Factory-method属性进 行的。

如果非静态工厂方法调用时也需要提供参数的话,处理方式是与静态的工厂方法相似的,都可以 通过<Constructor-arg>来指定方法调用参数。

FactoryBean

FactoryBean是Spring容器提供的一种可以扩展容器对象实例化逻辑的接口,请不要将其与容器 名称BeanFactory相混淆。FactoryBean, 其主语是Bean, 定语为Factory, 也就是说,它本身与其他注 册到容器的对象一样,只是一个Bean而已,只不过,这种类型的Bean本身就是生产对象的工厂 (Factory)。

当某些对象的实例化过程过于烦琐,通过XML配置过于复杂,使我们宁愿使用Java代码来完成这 个实例化过程的时候,或者,某些第三方库不能直接注册到Spring容器的时候,就可以实现org.spring­framework.beans.Factory.FactoryBean接口,给出自己的对象实例化逻辑代码。当然,不使用Fac­toryBean, 而像通常那样实现自定义的工厂方法类也是可以的。不过,FactoryBean可是Spring提供 的对付这种情况的“制式装备"哦!

要实现并使用自己的FactoryBean其实很简单,org.springframework.beans.Factory. FactoryBean只定义了三个方法,如以下代码所示:

getObject()方法会返回该FactoryBean "生产”的对象实例,我们需要实现该方法以给出自己 的对象实例化逻辑; getObj ectType ()方法仅返回getObject()方法所返回的对象的类型,如果预先 无法确定,则返回null; isSingleton()方法返回结果用于表明,工厂方法(getObject())所“生 产"的对象是否要以singleton形式存在于容器中。如果以singleton形式存在,则返回true, 否则返回false;

如果我们想每次得到的日期都是第二天,可以实现一个如代码清单

很简单的实现,不是嘛?

要使用NextDayDateFactoryBean, 只需要如下这样将其注册到容器即可:

配置上看不出与平常的bean定义有何不同,不过,只有当我们看到NextDayDateDisplayer的定 义的时候,才会知道FactoryBean的魅力到底在哪。NextDayDateDisplayer的定义如下

看到了嘛? NextDayDateDisplayer所声明的依赖dateOfNextDay的类型为DateTime, 而不是 NextDayDateFactoryBean。也就是说FactoryBean类型的bean定义,通过正常的id引用,容器返回

的是FactoryBean所“生产”的对象类型,而非FactoryBean实现本身。

如果一定要取得FactoryBean本身的话,可以通过在bean定义的id之前加前缀&来达到目的。代 码清单展示了获取FactoryBean本身与获取FactoryBean"生产”的对象之间的差别。

bean的方法替换与prototype得到最新对象

在学习以下内容之前,先提一下有关bean的scope的使用“陷阱",特别是prototype在容器中的使 用,以此引出本节将要介绍的Spring容器较为独特的功能特性:方法注入(Method Injection)以及方 法替换(Method Replacement)。

我们知道,拥有prototype类型scope的bean, 在请求方每次向容器请求该类型对象的时候,容器都 会返回一个全新的该对象实例。为了简化问题的叙述,我们直接将FXNews系统中的FXNewsBean定义 注册到容器中,并将其scope设置为prototype。因为它是有状态的类型,每条新闻都应该是新的独 立个体;同时,我们给出MockNewsPersister类,使其实现IFXNewsPersister接口,以模拟注入 FXNewsBean实例后的情况。这样,我们就有了代码清单所展示的类声明和相关配置。

当多次调用MockNewsPersister的persistNews时,你猜会得到什么结果?如下代码可以帮助我 们揭开答案:

从输出看,对象实例是相同的,而这与我们的初衷是相悖的。因为每次调用persistNews都会调 用getNewsBean()方法并返回一个FXNewsBean实例,而FXNewsBean实例是prototype类型的,因此每 次不是应该输出不同的对象实例嘛?

好了,问题实际上不是出在FXNewsBean的scope类型是否是prototype的,而是出在实例的取得方 式上面。虽然FXNewsBean拥有prototype类型的scope, 但当容器将—个FXNewsBean的实例注入 MockNewsPersister之后,MockNewsPersister就会一直持有这个FXNewsBean实例的引用。虽然每 次输出都调用了getNewsBean()方法并返回了FXNewsBean的实例,但实际上每次返回的都是 MockNewsPersister持有的容器第一次注入的实例。这就是问题之所在。换句话说,第一个实例注入 后,MockNewsPersister再也没有重新向容器申请新的实例。所以,容器也不会重新为其注入新的 FXNewsBean类型的实例。

知道原因之后,我们就可以解决这个问题了。解决问题的关键在于保证getNewsBean ()方法每次 从容器中取得新的FXNewsBean实例,而不是每次都返回其持有的单一实例。

方法注入

Spring容器提出了一种叫做方法注入(Method Injection)的方式,可以帮助我们解决上述问题。

我们所要做的很简单,只要让getNewsBean方法声明符合规定的格式,并在配置文件中通知容器,当 该方法被调用的时候,每次返回指定类型的对象实例即可。方法声明需要符合的规格定义如下:

也就是说,该方法必须能够被子类实现或者覆写,因为容器会为我们要进行方法注入的对象使用 Cglib动态生成一个子类实现,从而替代当前对象。既然我们的getNewsBean ()方法已经满足以上方法 声明格式,剩下唯一要做的就是配置该类,配置内容如下所示:

通过<lookup-method>的name属性指定需要注入的方法名,bean属性指定需要注入的对象,当 getNewsBean方法被调用的时候,容器可以每次返回一个新的FXNewsBean类型的实例。所以,这个时 候,我们再次检查执行结果,输出的实例引用应该是不同的:

注意 FXNewsBean的取得实际上可以在相应方法中按需要自行实例化,而不一定非要注册到 容器中,从容器中荻取。我们只是力了引入prototype的使用“陷阱“以及方法注入功能,才将 FXNewsBean以prototype类型注册到容器中供使用。当然,如果愿意你也可以以这种方式使用。 在最终输出的结果中,对象引用的数字不一定就是上面的那样。因为每次注入的实例是不同的, 所以对应实例的数字也可能不同。在此只需要关注每次同时输出的结果是否相同即可说明问 题。

除了使用方法注入来达到“每次调用都让容器返回新的对象实例”的目的,还可以使用其他方式 达到相同的目的。下面给出其他两种解决类似问题的方法。

使用BeanFactoryAware接口

我们知道,即使没有方法注入,只要在实现getNewsBean ()方法的时候,能够保证每次调用Bean­Factory的getBean ("newsBean"), 就同样可以每次都取得新的FXNewsBean对象实例。现在,我们唯 一要的,就是让MockNewsPersister拥有一个BeanFactory的引用。

Spring框架提供了一个BeanFactoryAware接口,容器在实例化实现了该接口的bean定义的过程 中,会自动将容器本身注入该bean。这样,该bean就持有了它所处的BeanFactory的引用。BeanFactory­Aware的定义如下代码所示:

我们让MockNewsPersister实现该接口以持有其所处的BeanFactory的引用,这样MockNews­Persister的定义如代码清单

实际上,方法注入动态生成的子类,完成的是与以上类似的逻辑,只不过实现细节上不同而已。

使用ObjectFactoryCreatingFactoryBean

ObjectFactoryCreatingFactoryBean是Spring 提供的一个FactoryBean实现,它返回一个ObjectFactory实例。从ObjectFactoryCreatingFactoryBean返回的这个ObjectFactory实例可以为我们返回容器管理的相关对象。

实际上, ObjectFactoryCreatingFactoryBean 实现了BeanFactoryAware接口,它返回的ObjectFactory实例只是特定于与Spring容器进行交互的一个实现而已。使用它的好处就是,隔离了客户端对象对BeanFactory的直接引用。现在,我们使用ObjectFactory取得FXNewsBean的实例,

有了以上的类定义之后,我们应该为MockNewsPersister注入相应的ObjectFactory, 这也正是 ObjectFactoryCreatingFactoryBean闪亮登场的时候

方法替换

与方法注入只是通过相应方法为主体对象注入依赖对象不同,方法替换更多体现在方法的实现层 面上,它可以灵活替换或者说以新的方法实现覆盖掉原来某个方法的实现逻辑。基本上可以认为,方 法替换可以帮助我们实现简单的方法拦截功能。要知道,我们现在可是在不知不觉中迈上了AOP的大 道哦!

假设某天我看FXNewsProvider不爽,想替换掉它的getAndPersistNews方法默认逻辑,这时, 我就可以用方法替换将它的原有逻辑给替换掉。

有了要替换的逻辑之后,我们就可以把这个逻辑通过<replaced-method>配置到FXNewsProv­ider的bean定义中,使其生效,配置内容如代码清单

最后需要强调的是,这种方式刚引入的时候执行效率不是很高。而且,当你充分了解并应用Spring AOP之后,我想你也不会再回头求助这个特色功能。不过,怎么说这也是—个选择,场景合适的话, 为何不用呢?

如果要替换的方法存在参数,或者对象存在多个重载的方法,可以在<replaced-method>内 部通过<arg-type>明确指定将要替换的方法参数类型。祝"替换"愉快!

IOC BeanFactory XML之旅相关推荐

  1. Spring IoC — 基于XML的配置

    1.属性注入 注意点: 1)如果类中显示定义了一个带参的构造函数,则一定还要显示提供一个无参构造函数,否则使用属性注入时将抛出异常. 2)JavaBean关于属性命名的特殊规范.Spring只会检查B ...

  2. Java学习笔记-Spring IoC 通过XML把Bean给IoC容器

    运行截图如下: 程序结构: 源码如下: Bean.java package springioc.demo.bean;public class Bean {public Bean(){System.ou ...

  3. @autowired注解原理_Spring框架第二谈:IOC,xml配置文件给属性赋值,注解实现赋值...

    在spring的对象文件中,给Java对象的属性赋值: di依赖注入,表示创建对象,给属性赋值di的实现方法有两种:1.在spring的配置文件中,使用标签完成,叫做基于XML的di实现2.使用spr ...

  4. spring应用手册-IOC(XML配置实现)-(8)-bean中的scop属性

    戴着假发的程序员出品 文字说明 看文字嫌累的可以查看后面的视频说明 scop属性用于指定bean的作用域.可以取一下几个值: singleton:单例模式(默认):    prototype:多例模式 ...

  5. spring应用手册-IOC(XML配置实现)-(23)-replaced-method标签

    戴着假发的程序员 出品 replaced-method标签 spring应用手册(第一部分) replaced-method可以让我们通过配置完成对原有的bean中的方法实现进行重新替换. 看案例: ...

  6. spring系统学习:20180607--Spring的 IOC 的XML和注解的整合开发

    转载于:https://www.cnblogs.com/JAVA-STUDYER/p/9152334.html

  7. 第4章 Spring的IoC容器之BeanFactory(四)

    BeanFactory的XML之旅 bean的继承 假设我们某一天需要对FXNewsProvider使用继承进行扩展,那么可能会声明如下代码所示的子类定义: class SpecificFXNewsP ...

  8. BeanFactory作为 IoC 容器示例

    /*** {@link BeanFactory} 作为 IoC 容器示例*/ public class BeanFactoryAsIoCContainerDemo {public static voi ...

  9. spring IOC基本配置(xml配置和注解配置)

    目录 Spring IOC IOC是什么 IOC可以做什么 依赖注入 IOC和DI IOC容器 Bean 配置IOC容器 spring ioc 依赖 XML配置 实例化容器 使用容器 xml配置详解 ...

最新文章

  1. shell学习之shell基础知识了解
  2. 【bzoj2081】[Poi2010]Beads Hash
  3. Node.js的3m安装法
  4. 展望2018,多媒体开发新趋势
  5. 驱动学习 - 加载.卸载驱动
  6. Knockout获取数组元素索引的2种方法,在MVC中实现
  7. 阿里云CDN直播架构与双11晚会直播实战
  8. 对WinForm的App.config文件进行加密
  9. 小D课堂 - 新版本微服务springcloud+Docker教程_2_03常见的微服务框架
  10. 选择Python科学计算发行版
  11. 生鲜电商进入2.0时代,美团还有“后招”吗?
  12. Linux电脑怎么接投影,linux如何连接投影机
  13. WebService接口大全
  14. 奥城大学计算机专业,美国研究生双录取的大学及可提供学位详情
  15. MATLAB地图工具箱学习总结(二)大圆和恒向线
  16. 打开栅格数据的正确方式
  17. java全能速查宝典_Java全能速查宝典_IT教程网
  18. 小程序源码:随机头像大全,多分类带历史记录-多玩法安装简单
  19. Spring实战笔记——(1)Spring之旅(上)
  20. Linux 往事:一个不会像 GNU 那样大而专业的 OS 是如何成为主流的?

热门文章

  1. Solr Server服务器端安装配置
  2. 告诉你60个经典的电脑使用技巧
  3. 晶圆检测显微镜是做什么研究才用到的?
  4. java 营业执照图片内容识别
  5. PIL+pyqt 写了一个图片批量无损压缩工具python
  6. A2M峰会直击|闲鱼纳米镜——人人都是数据分析师
  7. 快速生成不重复的卡号
  8. Java多线程面经整理
  9. 日落20181125001 - UGUI组件应用之Animation和CanvasGroup制作渐现渐隐效果
  10. MCV 和 MTV框架基本信息