Bean 类 id name&& bean的属性和合作者(声明与使用)

来源:互联网 发布:linux误删除文件恢复 编辑:程序博客网 时间:2024/06/05 09:36

Bean的类

Bean的class属性通常是强制性的,有两种方法。绝大多数情况下,BeanFactory直接调用bean的构造函数来“new”一个bean(相当于调用new的Java代码),class属性指定了需要创建的bean的类。在比较少的情况系,BeanFactory调用某个类的静态工厂方法来创建bean,class属性指定了实际包含静态工厂方法的那个类。(至于静态工厂方法返回的bean类型是同一个类还是完全不同的另一个类,这并不重要)。

 

通过构造函数创建bean

当使用构造函数创建bean时,所有普通的都可以被Spring使用并且和Spring兼容。即,被创建的类不需要实现任何特定的接口或者按照特定的样式进行编写。仅仅指定bean的类就足够了。然而,根据bean使用的IOC类型,你可能需要一个默认的(空的)构造函数。

 

另外,BeanFactory并不局限于管理真正的JavaBean,它也能管理任何你想让它管理的类。虽然很多使用Spring的人喜欢在BeanFactory中使用真正的JavaBean(仅包含一个默认的(无参数的)构造函数,在属性后面定义相对应的setter和getter方法),但是在你的JavaFactory中也可以使用特殊的非bean样式的类。举例来说,如果你需要使用一个遗留下来的没有完全遵守JavaBean规范的连接池,Spring也同样能够管理它。

 

 

使用XmlBeanFactory你可以像下面这样定义你的bean class(通过构造函数创建bean):

<bean id="exampleBean"

        class="examples.ExampleBean"/>

<bean name="anotherExample"

        class="examples.ExampleBeanTwo">

至于为构造函数提供(可选的)参数,以及对象实例创建后设置实例属性,后述。

 

通过静态工厂方法创建Bean

当你定义一个使用静态工厂方法创建的bean,同时使用class属性指定包含静态工厂方法的,这个时候需要factory-method属性来指定工厂方法名。Spring调用这个方法(包含一组可选的参数)并返回一个有效的对象,之后这个对象就完全和构造方法创建的对象一样。用户可以使用这样的bean定义在遗留代码中调用静态工厂。

 

下面是一个bean定义的例子,声明这个bean通过factory-method指定的方法创建。注意这个bean定义并指定返回对象的类型只指定包含工厂方法的类。在这个例子中,createInstance必须是static方法(通过构造函数创建bean):

<bean id="exampleBean"

   class="example.ExampleBean2"

   factory-method="createInstance"/>

至于为工厂方法提供(可选的)参数,以及对象实例被工厂方法创建后设置实例属性,后述。

 

通过实例工厂方法创建bean

使用一个实例工厂方法(非静态的)创建bean和使用静态工厂方法非常类似,调用一个已存在的bean(这个bean应该是工厂类型)的工厂方法来创建新的bean。

使用这种机制,class属性必须为,而且factory-bean属性必须指定一个bean的名字,这个bean一定要在当前的bean工厂或者bean工厂,并包含工厂方法。而工厂方法本身仍然要通过factory-method属性设置。

下面是一个例子(通过实例工厂方法创建bean):

<!--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本身能够被容器通过依赖注射来管理和配置。

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(用逗号,或者分号;分隔)

Singleton的使用与否

Beans被定义为两种部署模式中的一种:singleton或non-singleton。(后一种也叫作prototype,尽管这个名词用的不精确因为它并不是非常合适)。如果一个bean是singleton形态的,那么就只有一个共享的实例存在,所有和这个bean定义的id符合的bean请求都会返回这个唯一的、特定的实例。

 

如果bean以non-singleton,prototype模式部署的话,对这个bean的每次请求都会创建一个的bean实例。这对于例如每个user需要一个独立的user对象这样的情况是非常理想的。

 

beans默认被部署为singleton模式,除非你指定。要记住把部署模式变为non-singleton(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”操作符的替代品。从那之后的任何生命周期方面的事情都由客户端来处理。

 

属性,合作者,自动装配和依赖检查

设置bean的属性和合作者

反向控制通常与依赖注入同时提及。基本的规则是bean通过以下方式来定义它们的依赖(比如它们与之合作的其它对象):构造函数的参数工厂方法的参数;当对象实例被构造出来或从一个工厂方法返回后设置在这个实例上的属性容器的工作就是创建完bean之后,真正地注入这些依赖。这完全是和一般控制方式相反的(因此称为反向控制),比如bean实例化,或者直接使用构造函数定位依赖关系,或者类似Service Locator模式的东西。我们不会详述依赖注射的优点,很显然通过使用它:

代码变得非常清晰;当bean不再自己查找他们依赖的类而是由容器提供,甚至不需要知道这些类在哪里以及它们实际上是什么类型,这时高层次解耦也变得很容了。

正如上面提到的那样,反向控制/依赖注射存在两种主要的形式:

·基于setter的依赖注射,是在调用无参的构造函数或无参的静态工厂方法实例化你的bean之,通过调用你的bean上的setter方法实现的。在BeanFactory中定义的使用基于setter方法的注射依赖的bean是真正的JavaBean。Spring一般提倡使用基于setter方法的依赖注射,因为很多的构造函数参数将会是笨重的,尤其在有些属性是可选的情况下。

·基于构造函数的依赖注射,它是通过调用带有许多参数的构造方法实现的,每个参数表示一个合作者或者属性。另外,调用带有特定参数的静态工厂方法来构造bean可以被认为差不多等同的,接下来的文字会把构造函数的参数看成和静态工厂方法的参数类似。虽然Spring一般提倡在大多数情况下使用基于setter的依赖注射,但是Spring还是完全支持基于构造函数的依赖注射,因为你可能想要在那些只提供多参数构造函数并且没有setter方法的遗留的bean上使用Spring。另外对于一些比较简单的bean,一些人更喜欢使用构造函数方法确保bean不会处于错误状态。

BeanFactory同时支持这两种方式将依赖注射到被管理bean中。(实际上它还支持在一些依赖已经通过构造函数方法注射后再使用setter方法注射依赖)。依赖的配置是以BeanDefinition的形式出现,它和JavaBean的PropertyEditors一起使用从而知道如何把属性从一个格式转变为另一个。真正传送的值被封装为PropertyValue对象。然而,大多数Spring的使用者并不要直接(比如编程的方式)处理这些类,而更多地使用一个XML定义文件,这个文件会在内部被转变为这些实例,用来读取整个BeanFactory或ApplicationContext。

 

Bean依赖的决定通常取决于下面这些内容:

1.BeanFactory通过使用一个描述所有bean的配置被创建和实例化。大多数的Spring用户使用一个支持XML格式配置文件的BeanFactory或ApplicationContext实现。

2.每一个bean的依赖表现为属性构造函数参数,或者当用静态工厂方法代替普通构造函数时工厂方法的参数。这些依赖将会bean真正被创建出来供给bean

3.每一个属性或者构造函数参数要么是一个要被设置的值的定义,要么是一个指向BeanFactory中其他bean的引用。在ApplicationContext的情况下,这个引用可以指向一个父亲ApplicationContext中的bean。

4.每一个属性或构造函数参数的值,必须能够从(配置文件中)被指定的格式转变为真实类型。缺省情况下,Spring能够把一个字符串格式的值转变为所有内建的类型,比如int,long,String,boolean等等。另外当说到基于XML的BeanFactory实现的时候(包括ApplicationContext实现),它们已经为定义Lists,Maps,Sets和Properties集合类型提供了内在的支持。另外,Spring通过使用JavaBeans的PropertyEditor定义,能够将字符串值转变为其他任意的类型。(你可以为PropertyEditor提供你自己的PropertyEditor定义从而能够转变你自定义的类型)。当一个bean属性是一个Java Class类型,Spring允许你用这个类的名字的字符串作为这个属性的值,ClassEditor这个内建的PropertyEditor会帮你把类的名字转变成真实的Class实例。

5.很重要的一点就是:Spring在BeanFactory创建的时候要校验BeanFactory中的每一个Bean的配置。这些校验包括作为Bean引用的属性必须实际引用一个合法的bean(比如被引用的bean也定义在BeanFactory中,或者当ApplicationContext时,在父亲ApplicationContext中)。但是,bean属性本身知道bean被真实建立的时候才被设置。对于那些是singleton并且被设置为pre-instantiated的bean来说(比如一个ApplicationContext中的singletonbean),bean在创建BeanFactory的时候创建,但是对于其他情况,发生在bean被请求的时候。当一个bean必须被创建时,它会潜在地导致一系列的其它bean被创建,像他的依赖以及它的依赖的依赖(如此下去)被创建和赋值。

6.通常你可以信任Spring做了正确的事情。它会在BeanFactory装载的时候检查出错误,包括对不存在bean的引用和循环引用。它会尽可能晚地设置属性和解决依赖(比如创建那些需要的依赖),也就是在bean被真正创建的时候。这意味着:就算一个BeanFactory被正确地装载,稍后当你请求一个bean的的时候,如果创建那个bean或者它的依赖的时候出现了错误,这个BeanFactory也会抛出一个异常。比如,如果一个bean抛出一个异常作为缺少或非法属性的结果,这样的情况就会发生。这种潜在地推迟一些配置错误可见性的行为正是ApplicationContext默认预实例化singleton bean的原因。以前期的时间和内存为代价在beans真正需要之前创建它们,你就可以在ApplicationContext创建的时候找出配置错误,而不是在后来。如果你愿意,你也可以覆盖这种默认行为,设置这些singleton bean为lazy-load(不是预实例化的)。

 

几个例子:

 

首先,一个使用BeanFactory以及基于setter方法的依赖注射。下面是一个定义了一些bean的XmlBeanFactory配置文件的一小部分。接下去是正式的bean代码,演示了正确的setter方法声明。

 

<bean id="exampleBean" class="examples.ExampleBean">

<property name="beanOne"><ref bean="anotherExampleBean"/></property>

<property name="beanTwo"><ref bean="yetAnotherBean"/></property>

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

</bean>

 

<bean id="anotherExampleBean" class="examples.AnotherBean"/>

<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

 

 

 

public class ExampleBean{

private AnotherBean beanOne;

private YetAnotherBean beanTwo;

private int i;

public void setBeanOne(AnotherBean beanOne){

this.beanOne=beanOne;

}

public void setBeanTwo(YetAnotherBean beanTwo){

this.beanTwo=beanTwo;

}

public void setIntegerProperty(int i){

this.i=i;

}

}

正如你所看到的一样,setter方法被声明以符合XML文件中指定的属性。(XML文件中的属性,直接对应着RootBeanDefinition中的PropertyValues对象)

接着是一个使用了IOC type3(基于构造函数的依赖注射)的BeanFactory。下面是XML中的一段配置,指定了构造函数参数以及展示构造函数的代码:

<bean id="exampleBean" class="examples.ExampleBean">

<constructor-arg><ref bean="anotherExampleBean"/></constructor-arg>

<constructor-arg><ref bean="yetAnotherBean"/></constructor-arg>

<constructor-arg><value>1</value></constructor-arg>

</bean>

 

<bean id="anotherExampleBean" class="examples.AnotherBean"/>

<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

 

 

public class ExampleBean{

 

private AnotherBean beanOne;

private YetAnotherBean beanTwo;

private int i;

Public ExampleBean(AnotherBean anotherBean,YetAnotherBean,int i){

this.beanOne=anotherBean;

this.beanTwo=anotherBean;

this.i=i;

}

}

 

正如你所看到的,bean定义中指定的构造函数的参数将会作为ExampleBean的构造函数参数被传入。

 

现在考虑一下不用构造函数,而是调用一个静态工厂方法来返回一个对象的实例:

<bean id="exampleBean" class="examples.ExampleBean"

factory-method="createInstance">

<constructor-arg><ref bean="anotherExampleBean"/></constructor-arg>

<constructor-arg><ref bean="yetAnotherBean"/></constructor-arg>

<constructor-arg><value>1</value></constructor-arg>

</bean>

 

<bean id="anotherExampleBean" class="examples.AnotherBean"/>

<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

 

 

public class ExampleBean{

 

...

 

//a private constructor

private ExampleBean(...){

...

}

//a static factory method

//the arguments to this method can be considered the dependencies of the bean that

//is retured,regardless of how those arguments are actually used

public static ExampleBean Example(AnotherBean anotherBean,yetAnotherBean yetAnotherBean,int i){

ExampleBean eb=new ExampleBean(...);

//some other operations

...

return eb;

}

}

 

需要注意的是:静态工厂方法参数constructor-arg元素提供,这和构造函数的用法是一样的。这些参数是可选的。重要的一点是工厂方法所返回对象类型不一定和包含这个静态工厂方法的类一致,虽然上面这个例子中是一样的。前面所提到的实例工厂方法(non-static

用法基本上是一样的(除了使用factory-bean属性代替class属性)。

原创粉丝点击