先从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为我们带来的模块的松耦合和应用的便利性。

那为什么说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!"); 
        } 
    } 

……

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

在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容器中获取HelloWorld的实例的时候就会new一个新对象,即我们所说的原型,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>

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

<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的,我们的配置如下:

<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注入的原因之一。

最新文章

  1. Android进阶--Acticivity的启动模式
  2. devexpress treelist 过滤
  3. mysql 语法总结
  4. 使用CodeSmith快速生成映射文件和映射类
  5. python(6)-logging 日志模块
  6. 在centos 6.4下安装opencv 2.3.1
  7. python脚本实例002- 利用requests库实现应用登录
  8. PHP中的session会话创建打印释放销毁;
  9. (08)DBA写给开发的索引经验
  10. 【长 PI】
  11. Spring Boot HTTP over JSON 的错误码异常处理
  12. 开启SSH
  13. 定位 position 透明度 opacity
  14. 自动化测试badboy脚本开发(一)
  15. 搭建RESTful API来使用Fabric Node SDK 开篇
  16. spring boot IDEA 开发微服务(二)
  17. [ES]ES查询指南
  18. PHP 验证IP的合法性
  19. vconsole h5应用ajax请求抓包
  20. POJ 2965 The Pilots Brothers&#39; refrigerator (DFS)

热门文章

  1. android开源项目---blog篇
  2. C++命名空间&lt;转&gt;
  3. OSPF
  4. javascript输出图的简单路径
  5. tomcat maven book
  6. PgSQL &#183; 特性分析 &#183; 谈谈checkpoint的调度
  7. 【转】DBMS_STATS.GATHER_TABLE_STATS详解 2012-04-22 09:20:10
  8. OpenJudge就算概论-统计字符数
  9. JavaScript中类的实现机制
  10. 转:GBDT(MART) 迭代决策树入门教程 | 简介