Spring中Bean的配置

先从IOC提及,这个概念实际上是从咱们日常new一个对象的对立面来讲的,咱们日常使用对象的时候,通常都是直接使用关键字类new一个对象,那这样有什 么坏处呢?其实很显然的,使用new那么就表示当前模块已经不知不觉的和new的对象耦合了,而咱们一般都是更高层次的抽象模块调用底层的实现模块,这样 也就产生了模块依赖于具体的实现,这样与咱们JAVA中提倡的面向接口面向抽象编程是相冲突的,并且这样作也带来系统的模块架构问题。很简单的例子,咱们 在进行数据库操做的时候,老是业务层调用DAO层,固然咱们的DAO通常都是会采用接口开发,这在必定程度上知足了松耦合,使业务逻辑层不依赖于具体的数 据库DAO层。可是咱们在使用的时候仍是会new一个特定数据库的DAO层,这无形中也与特定的数据库绑定了,虽然咱们可使用抽象工厂模式来获取DAO 实现类,但除非咱们一次性把全部数据库的DAO写出来,不然在进行数据库迁移的时候咱们仍是得修改DAO工厂类。

    那咱们使用IOC能达到什么呢?IOC,就是DAO接口的实现再也不是业务逻辑层调用工厂类去获取,而是经过容器(好比spring)来自动的为咱们的业务 层设置DAO的实现类。这样整个过程就反过来,之前是咱们业务层主动去获取DAO,而如今是DAO主动被设置到业务逻辑层中来了,这也就是反转控制的由 来。经过IOC,咱们就能够在不修改任何代码的状况下,无缝的实现数据库的换库迁移,固然前提仍是必须得写一个实现特定数据库的DAO。咱们把DAO广泛 到更多的状况下,那么IOC就为咱们带来更大的方便性,好比一个接口的多个实现,咱们只须要配置一下就ok了,而不须要再一个个的写工厂来来获取了。这就 是IOC为咱们带来的模块的松耦合和应用的便利性。 java

那为何说IOC很简单呢?说白了其实就是由咱们日常的new转成了使用反射来获取类的实例,相信任何人只要会用java的反射机制,那么本身写一个IOC框架也不是不可能的。好比:

……
public Object getInstance(String className) throws Exception
{
    Object obj = Class.forName(className).newInstance();
    Method[] methods = obj.getClass().getMethods();
    for (Method method : methods) {
        if (method.getName().intern() == "setString") {
            method.invoke(obj, "hello world!");
        }
    }
}
…… web

  上面的一个方法咱们就很简单的使用了反射为指定的类的setString方法来设置一个hello world!字符串。其实能够看到IOC真的很简单,固然了IOC简单并不表示spring的IOC就简单,spring的IOC的功能强大就在于有一系 列很是强大的配置文件维护类,它们能够维护spring配置文件中的各个类的关系,这才是spring的IOC真正强大的地方。在spring的Bean 定义文件中,不只能够为定义Bean设置属性,还支持Bean之间的继承、Bean的抽象和不一样的获取方式等等功能。 spring

在spring的Bean配置中总的来讲其实就一个标签<bean></bean>,这个bean标签就攘括了几乎全部的配置, 而后bean的继承、抽象等都是基于此标签之上的,掌握了bean的配置,详细可使本身有一个比较大的提高,尤为是对于新手来讲(我也是,呵呵  )。最基础的bean配置以下:

<bean id="bean_test" class="cn.qtone.test.HelloWorld"></bean>

    这里咱们就简单的使用HelloWorld类来实例化,使用默认的构造方法,即至关于咱们使用:

HelloWorld tmp = new HelloWorld();  数据库

但有一点不一样的是在spring配置中的在整个应用期间只有一个实例,便是单例的,固然这个单例是指对一个IOC容器(spring)来讲的,而不是咱们一般说说的单态模式。固然,spring也能够这样配置不是单态的实例,好比咱们修改以下:

<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype"></bean>

  spring中scope默认的是单态(singleton),固然针对web应用程序,还能够配置为request、session等范围。至于什 么时候使用什么权限范围就要看应用程序的使用了,好比在多线程程序中,单态是否会对程序有所影响就须要考虑了。 编程

若是HelloWorld类没有空的构造方法,只有以下的两个构造方法,那咱们该如何配置呢?

……
public HelloWorld(String str)
{
    ……
}

public HelloWorld(Date date, int i)
{
    ……
}
……

    因为没有默认构造方法,因此咱们就须要在bean的配置中写上构造参数才能够,以下:

<!-- 使用一个参数的构造 -->
<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype">
    <constructor-arg><value>hello</value></constructor-arg>
</bean> session

   上面说的使用一个参数的,即带字符串参数的构造方法,若是想使用带日期和整型的构造方法,那么就要作以下的配置了:

<bean id="bean_date" class="java.util.Date" />

<!-- 使用二个参数的构造 -->
<bean id="bean_test" class="cn.qtone.test.HelloWorld" 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" class="cn.qtone.test.HelloWorld" 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的,咱们的配置以下: spa

<bean id="bean_string" class="cn.qtone.test.TestFactory" 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" class="cn.qtone.test.TestBeanFactory"/>

<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" class="cn.qtone.test.HelloWorld">
    <property name="hello" 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注入的缘由之一。

相关文章
相关标签/搜索