(Spring-bean)生命周期接口、FactoryBean、BeanFactory交互、子bean

来源:互联网 发布:网购牛奶 知乎 编辑:程序博客网 时间:2024/05/24 03:56

依赖检查

对于部署在BeanFactory的bean的未解决的依赖,Spring有能力去检查他们的存在性。这些依赖要么是bean的JavaBean式的属性,在bean的定义中并没有为它们设置真实的值,要么是通过自动装配特性被提供。

当你想确保所有的属性(或者某一特定类型的所有属性)都被设置到bean上面的时候,这些特性就很有用了。当然,在很多情况下一个bean类的很多属性都会有缺省的值,或者一些属性并不会应用到所有的应用场景,那么这个特性的作用就有限了。依赖检查能够分别对每一个bean应用或取消应用,就像自动装配一样。缺省的是不检查依赖关系。依赖检查可以以几种不同的模式处理。在XmlBeanFactory中,通过bean定义中的dependency-check属性来指定依赖检查,这个属性有以下的值:

 

依赖检查模式

模式

解释

none

不进行依赖检查。没有指定值的bean属性仅仅是没有设值。

simple

对基本类型和集合(除了合作者外,比如其他的bean,所有东西)进行依赖检查。

object

对合作者进行依赖检查。

all

对合作者、基本类型和集合都进行依赖检查。

 

自定义bean的本质特征

生命周期接口

Spring提供了一些标志接口,用来改变BeanFactory中的bean的行为。它们包括InitializingBean和DisposableBean。实现这些接口将会导致BeanFactory调用前一个接口的afterPropertiseSet()方法,调用后一个接口destroy()方法,从而使得bean可以在初始化和析构后做一些特定的动作。

在内部,Spring使用BeanPostProcessors来处理它能找到的标志接口以及调用适当的方法。若需要自定义的特性或者其他的Spring没有提供的生命周期行为,可以实现自己的BeanPostProcessor。

 

 

InitializingBeanBean / init-method

实现org.springframework.beans.factory.InitializingBean接口允许一个bean在它所有必须的属性被BeanFactory设置后,来执行初始化的工作。InitializingBean接口仅仅指定了一个方法:

* Invoked by a BeanFactory after it has set all bean properties supplied

* (and satisfied BeanFactoryAware and ApplicationContextAware).

* <p>This method allows the bean instance to perform initialization only

*possible when all bean properties have been set and to throw an exception in the event of misconfiguration.

*@throws Exception in the event of misconfiguration(such as failure to set an essential property)or if initialization falls.

*/

void afterPropertiesSet() throws Exception;

 

注意:通常InitializingBean接口的使用是能够避免的(而且不鼓励,因为没必要把代码同Spring耦合起来)。Bean的定义支持指定一个普通的初始化方法。在使用XmlBeanFactory的情况下,可以通过指定init-method属性来完成。举例来说,下面的定义:

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>

public class ExampleBean{

public void init(){

//do some initialization work

}

}

 

同下面的完全一样:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>

public class AnotherExampleBean implements InitializingBean{

public void afterPropertiesSet(){

//do some initialization work

}

}

但却不把代码耦合与Spring

DisposableBean / destroy-method

实现org.springframework.beans.factory.DisposableBean接口允许一个bean,可以在包含它的BeanFactory销毁的时候得到一个回调。DisposableBean也指定了一个方法:

/**

*Invoked by a BeanFactory on destruction od a singleton

*@throws Exception in case of shutdown errors.

*Exception will get logged but not rethrown to allow other beans to release their resources too.

*/

void destroy() throws Exception;

注意:通常DisposableBean接口的使用是能够避免的(而且不鼓励,因为没必要把代码同Spring耦合起来)。Bean的定义支持指定一个普通的析构方法。在使用XmlBeanFactory的情况下,可以通过指定destroy-method属性来完成。举例来说,下面的定义:

<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="destroy"/>

public class ExampleBean{

public void cleanup(){

//do some destruction work(like closing connection)

}

}

 

同下面的完全一样:

<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>

public class AnotherExampleBean implements DisposableBean{

public void destroy(){

//do some destruction work

}

}

但却不把代码耦合与Spring

重要提示:当以prototype模式部署一个bean的时候,bean的生命周期将会有少许的变化。通过定义,Spring无法管理一个non-singleton/prototype bean的整个生命周期,因为当它创建之后,它被交给客户端而且容器根本不再留意它了。当说起non-singleton/prototype bean的时候,你可以把Spring的角色想象成“new”操作符的替代品。从那之后的任何生命周期方面的事情都由客户端来处理。

 

BeanFactoryAware

对于实现了org.springframework.beans.factory.BeanFactoryAware接口的类,当它被BeanFactory创建后,它会拥有一个指向创建它的BeanFactory的引用。

 

public interface BeanFactoryAware{

/**

* Callback that supplies the owning factory to a bean instance.

* <p>Invoked after population of normal bean properties but before an init

* callback like InitializingBeans afterPropertiesSet or a custom init-method.

* @param beanFactory owing BeanFactory(may not be null).

* The bean can immediately call methods on the factory.

* @throw BeanException in case of initializaion errors

* @see BeanInitializationException

*/

void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

 

这允许bean可以以编程的方式操控创建它们的BeanFactory,既可以直接使用org.springframework.beans.factory.BeanFactory接口,也可以将引用强制将类型转换为已知的子类型从而获得更多的功能。这个特性主要用于编程式地取其他bean。虽然在一些场景下这个功能是有用的,但是一般来说它应该避免使用,因为它使代码与Spring耦合在一起,而且也不遵循反向控制的风格(合作者应当作属性提供给bean)。

 

BeanNameAware

如果一个bean实现了org.springframework.beans.factory.BeanNameAware接口,并且被部署到一个BeanFactory中,那么BeanFactory就会通过这个接口来调用bean,以便通知这个bean它被部署的id。这个回调发生在普通的bean属性设置之后,在初始化回调之前,比如InitializingBeanafterPropertiesSet方法(或者自定义的init-method)。

 

FactoryBean

接口org.springframework.beans.factory.FactoryBean一般由本身是工厂类的对象实现。BeanFactory接口提供了三个方法:

·Object getObject():必须返回一个这个工厂类创建的对象实例。这个实例可以是共享的(取决于这个工厂返回的是singleton还是prototype)。

·boolean isSingleton():如果Factory返回的对象是singleton,返回true,否则返回false

·Class getObjectType():返回getObject()方法返回的对象的类型,如果类型不是预先知道的,则返回null

 

 

bean定义

一个bean定义可能会包含大量的配置信息,包括容器相关的信息(比如初始化方法,静态工厂方法名等等)以及构造函数参数和属性的值。一个子bean定义是一个能够从父bean定义继承配置数据的bean定义。它可以覆盖一些值,或者添加一些其他需要的值。使用父和子的bean定义可以节省很多输入工作。实际上,这就是一种模板形式。

 

当以编程的方式使用一个BeanFactory,子bean定义用ChildBeanDefinition类表示。大多数的用户从来不需要以这个方式使用它们,而是在类似XmlBeanFactoryBeanFactory中以声明的方式配置bean定义。在一个XmlBeanFactorybean定义中,使用parent属性指出一个子bean定义,而父bean则作为这个属性的值。

<bean id="inheritedTestBean" class="org.springframework.beans.TestBean">

    <property name="name"><value>parent</value></property>

    <property name="age"><value>1</value></property>

</bean>

 

<bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize">

    <property name="name"><value>override</value></property>

    <--age should inherit value of 1 from parent-->

</bean>

 

如果子bean定义没有指定class属性,将使用父定义的class属性,当然也可以覆盖它。在后面一种情况中,子bean的class属性值必须同父bean的兼容,也就是它必须能够接受父亲的属性值。

一个子bean定义可以从父亲处继承构造函数参数,属性值以及方法,并且可以选择增加新的值。如果init-method,destroy-method和/或静态factory-method被指定了,它们就会覆盖父亲相应的设置。

 

剩余的设置将总是从子定义处得到:依赖,自动装配模式,依赖检查,singleton,延迟初始化。在下面的例子中父定义并没有指定class属性:

<bean id="inheritedTestBeanWithoutClass">

    <property name="name"><value>parent</value></property>

    <property name="age"><value>1</value></property>

</bean>

 

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBeanWithoutClass" init-method="initialize">

    <property name="name"><value>override</value></property>

    <!--age should inherit value of 1 from parent-->

</bean>

 

这个父bean就无法自己实例化;它实际上仅仅是一个纯模板或抽象bean,充当子定义的父定义。若要尝试单独使用这样的父bean(比如将它作为其他bean的ref属性而引用,或者直接使用这个父bean的id调用getBean()方法),将会导致一个错误。同样地,容器内部的preInstantiateSingletons方法会完全忽略这种既没有parent属性也没有class属性的bean定义,因为它们是不完整的。

 

特别注意:这里并没有办法显式地声明一个bean定义为抽象的。如果一个bean确实有一个class属性定义,那么它就能够被实例化。而且要注意XmlBeanFactory默认地将会预实例化所有的singleton的bean。因此很重要的一点是:如果你有一个(父)bean定义指定了class属性,而你又想仅仅把它当做模板使用,那么你必须保证将lazy-init属性设置为true(或将bean标记为non-singleton),否则XmlBeanFactory(以及其他可能的容器)将会预实例化它。

 

BeanFactory之间的交互

BeanFactory本质上不过是高级工厂的接口,它维护不同bean和它们所依赖的bean的注册。

BeanFactory使得你可以利用bean工厂读取和访问bean定义。当你使用BeanFactory的时候,你可以像下面一样创建并且读入一些XML格式的bean定义:

InputStream is = new FileInputStream("beans.xml");

XmlBeanFactory factory = new XmlBeanFactory(is);

 

基本上这就足够了。使用getBean(String)你可以取得你的bean实例。如果你将它定义为一个singleton(缺省的)你将会得到同一个bean的引用,如果你将singleton设置为false,那么你将会每次得到一个新的实例。在客户端的眼里BeanFactory是惊人的简单。BeanFactory接口仅仅为客户端调用提供了5个方法:

· boolean containsBean(String):如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true

· Object getBean(String):返回一个以所给名字注册的bean的实例。返回一个singleton的共享的实例还是新建一个实例,这取决于bean在BeanFactory配置中如何被配置的。一个BeansException将会在下面两种情况中抛出:bean没有被找到(在这种情况下,抛出的是NoSuchBeanDefinitionException),或者在实例化和准备bean的时候发生异常。

·Object getBean(String,Class):返回一个以给定名字注册的bean。返回的bean将会被强制类型转换成给定的class。如果bean不能被类型转换,相应的异常将会被抛出(BeanNotOfRequiredTypeException)。此外getBean(String)的所有规则也同样适用这个方法(同上)

·boolean isSingleton(String):判断以给定名字注册的bean定义是一个singleton还是一个prototype。如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)

·String[] getAliases(String):如果给定的bean名字在bean定义中有别名,则返回这些别名

 

获得一个FactoryBean而不是它生成的bean

有时候我们需要向BeanFactory请求实际的FactoryBean实例本身,而不是它生产出来的bean。在调用BeanFactory(包括ApplicationContext)的getBean方法的时候,在传入的参数bean id前面加一个“&”符号,就可以做到这一点。所以,对于一个id为getBean的FactoryBean,在BeanFactory上调用getBean(“myBean”)将会返回FactoryBean的产品,而调用getBean(“&myBean”)将会返回这个FactoryBean实例本身。

原创粉丝点击