从spring的IOC说起(二)——spring的Bean的基础配置(转)
上次简单的说了下spring的IOC,也说到了spring的IOC强大在于有一系列可以维护Bean不同关系的维护类的存在,而这样的维护也是基于高度可配置的spring配置文件而言的。这次就是结合我的使用spring的IOC来讲讲我在使用中的体会,当然,这里涉及的内容不会很高深,但是也必须读者能够读懂简单的Bean配置才可以。
我们这里只讲spring的IOC,AOP不在这范围之内,虽然AOP也是基于IOC之上的,至于那些集合啊什么的配置也不是这里的重点。我们这里说spring的Bean配置,主要就是说如何配置Bean在配置文件中,可以使结构更加合理化和使我们的编写量更少,当然我所说的也不一定对,也是和大家一起讨论讨论:),也希望大家可以提出更好的方法或模式。
在spring的Bean配置中总的来说其实就一个标签<bean></bean>,这个bean标签就攘括了几乎所有的配置,然后bean的继承、抽象等都是基于此标签之上的,掌握了bean的配置,详细可以使自己有一个比较大的提升,尤其是对于新手来说(我也是,呵呵 )。最基础的bean配置如下:
<bean id="bean_test" name="code">HelloWorld tmp = new HelloWorld();
?
但有一点不同的是在spring配置中的在整个应用期间只有一个实例,即是单例的,当然这个单例是指对一个IOC容器(spring)来说的,而不是我们通常说说的单态模式。当然,spring也可以这样配置不是单态的实例,比如我们修改如下:
<bean id="bean_test" scope="prototype"></bean>
?
注意其中的不同颜色部分,这样配置后就表明每次从spring容器中获取HelloWorld的实例的时候就会new一个新对象,即我们所说的原型,spring中scope默认的是单态(singleton),当然针对web应用程序,还可以配置为request、session等范围。至于什么时候使用什么权限范围就要看应用程序的使用了,比如在多线程程序中,单态是否会对程序有所影响就需要考虑了。
如果HelloWorld类没有空的构造方法,只有如下的两个构造方法,那我们该如何配置呢?
……public HelloWorld(String str){ ……}
?
public HelloWorld(Date date, int i){ ……}……
?
由于没有默认构造方法,所以我们就需要在bean的配置中写上构造参数才可以,如下:
?
<!-- 使用一个参数的构造 --><bean id="bean_test" scope="prototype"> <constructor-arg><value>hello</value></constructor-arg></bean>
?
上面说的使用一个参数的,即带字符串参数的构造方法,如果想使用带日期和整型的构造方法,那么就要做如下的配置了:
<bean id="bean_date" />
?
<!-- 使用二个参数的构造 --><bean id="bean_test" scope="prototype"> <constructor-arg ref="bean_date"></constructor-arg> <constructor-arg><value>345</value></constructor-arg></bean>
?
注意到上面的配置中我们使用了ref关键字,这个是表示引用配置文件中的ID为bean_date的对象,另外对于类型,spring会做恰当的转换,比如将345转换成数字等。当然,这样对简单的构造来说不会有什么问题,如果情况比较复杂的话,那么一般建议使用序号来标定,如下:
<!-- 使用二个参数的构造 --><bean id="bean_test" scope="prototype"> <constructor-arg index="0"ref="bean_date"></constructor-arg> <constructor-arg index="1"><value>345</value></constructor-arg></bean>
?
这样,使用index属性表示该参数所在位置了后,无论是spring构造起来,还是我们查看都会很方便。当然,spring也提供了自动查找,也就是依赖查找的功能,但是这个我觉得大家还是少用,因为这样会使整个配置文件看起来非常的不直观,而且不清晰,说不定过了一段时间再去看的时候就不知道是什么意思了,在正式应用项目中,还是将各个bean的关系进行组织和编写清楚为好。
上面所说的都是构造来实例化一个bean,但有时候我们都会使用工厂模式来获取bean。对于工厂模式,我们一般也使用静态工厂模式和实例工厂模式,这两个在spring中配置也是不太一样的。对于静态工厂模式来实例化bean的,我们的配置如下:
<bean id="bean_string" factory-method="getBean"/>
?
当然,我们也可以为静态工厂模式的bean来使用构造参数,这个就不说了。我们上面的bean配置对应的实际代码就应该是:
……public static Object getBean(){ return "hello world";}……
?
那么spring在实例化ID为bean_string的bean时,就会使用TestFactory的getBean()方法来获取,而且TestFactory是没有被实例化的,即是使用静态方法来获取的。对于实例工厂模式的话,我们的配置和上面就稍微有点不一样了,那我们就应该配置两个bean, 一个是实例的工厂bean,还一个就是我们要获取的bean的配置了,如下:
<bean id="bean_factory" name="code"><bean id="bean_helloWorld" factory-bean="bean_factory" factory-method="getHello"/>
?
上面的配置中,spring容器将首先实例化一个TestBeanFactory,然后再根据该类的方法getHello来获取一个bean的实例,我们这里以HelloWorld对象为例,对应的代码就应该如下:
……public HelloWorld getHello(){ return new HelloWorld();}……
?
注意到,我们这里的getHello方法并不是静态方法,而是实例方法,所以必须先实例化TestBeanFactory后才能够调用。
上面说的都是如何去实例化一个bean,没有说到bean的属性注入。虽然我们也可以通过构造的时候进行一次注入,但这样做不仅失去了灵活性,而且一长串的构造参数看着也眼疼哈,呵呵。当然,有一种情况下,我们是应该使用构造注入的,就是希望注入的对象不能够被外界修改时,我们这时候就必须使用构造注入了。对于bean的属性注入,以HelloWorld为例,我们可以简单的配置如下:
<bean id="bean_test" value="你好!" /> <property name="world" value="世界" /> <property name="date" ref="bean_date" /></bean>
?
上面的配置中使用了三个属性注入,即spring中的setter注入方式。注意第三个属性,使用了ref,表明这个date属性的设置参数是关联到ID为bean_date的bean上去的。注意在使用setter注入的时候,属性的名称不是方法的全名称,而是满足javaBean规范的命名方式,即如果属性名称为xxx,那么其对应的方法名称就应该是:setXxx(),注意的是除了xxx中第一个字符不区分大小写之外,其他的是要严格区分的。那么对照上面的配置,我们的HelloWorld的方法就应该如下:
……public void setHello(String hello){ ……}public void setWorld(String world){ ……}public void setDate(Date date){ ……}……
?
使用setter注入的好处就是可以很清晰的知道每一个注入的是什么参数和意义,通过名称就可以很容易的看出来,这也是spring提倡使用setter注入的原因之一。
今天就简单的说下spring的bean的基础配置,包括bean的实例化和属性的注入等。下次就讲下配置中的bean的继承、抽象等话题。