1.Spring框架中的IoC
1)控制反转(Inversion of Control,IoC)
所谓控制反转,就是将应用系统中原来由程序控制“对象之间的关系”转交给由外部容器来实现控制。借助于控制反转的机制,能够实现由容器控制程序中的各个类之间的关系,而非传统形式的编程实现中直接在程序代码中由程序代码操控各个类对象实例之间的关系。
这就是“控制反转”的概念:控制权由应用系统中的程序代码转移到了外部容器。控制权的转移,即“控制反转”;利用“控制反转”能够减少对象的请求者对服务提供者的特定实现逻辑的依赖,因为应用系统中的各个组件类不再需要去查找或是实例化它们所依赖的其他目标组件类。
2)IoC是一种使应用程序逻辑外在化的设计模式
在这种编程模式下,提供服务的目标组件是被“注入”的而不是被“直接写入”到请求者(客户端)的代码中;这样将大大减少对象的请求者对服务提供者的特定实现逻辑的依赖。因为开发者已经将依赖的具体“定位信息”和“关系信息”从请求者中分离出来了,而在Spring框架中则是将它们放在IoC的*.XML的配置文件中。
3)应用Spring 框架中的IoC进行系统开发时的基本要求
为了能够更好地应用Spring框架中的IoC技术,对开发者在具体编程方面也有一定的要求。也就是在代码中不应该再直接创建出目标对象的实例,而应该只描述出创建它们的方式。即在代码中不直接与服务对象连接,但需要在配置文件(一般为*.XML文件)中描述出应用系统中的哪一个功能组件需要哪一项服务。应用系统中的组件类程序在运行时,由容器(在 Spring 框架中是指 IoC 容器)负责将这些对象关联在一起,并依据调用关系将目标对象注入。
4)应用Spring框架中的IoC的代码示例
在下面的Spring框架中的IoC的*.XML文件的示例中声明了两个对象,名称分别为theUpperAction和theLowerAction。在运行过程中,由Spring框架中的IoC容器并分别为该两个对象动态注入属性字符串值。请参见【例1-1】中的代码,并请注意其中黑体部分的代码。
1-1 应用Spring框架中的IoC容器的代码示例。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
实例化配置的对象,以配置文件的bean节点ID值作为实例引用的关键字 |
<beans>
<bean id="theUpperAction"
class="com.px1987.springexample.springj2seapp.
UpperTrnsferAction">
<property name="messageProperty">
<value>HeLLo,UpperAction </value>
它会被动态地注入到UpperTrnsferAction的messageProperty属性中 |
</bean>
<bean id="theLowerAction" class="com.px1987.springexample.
springj2seapp.LowerTrnsferAction">
<property name="messageProperty">
<value>HeLLo,LowerAction </value>
它会被动态地注入到LowerTrnsferAction的messageProperty属性中 |
</bean>
</beans>
2.Spring 框架中的依赖注入DI技术
1)依赖注入(Dependency Injection,DI)是对IoC的另一种描述
当初Rod Johnson提出IoC的概念时,曾经引起业界的争论。因为在 IoC的概念中没有具体说明如何实现控制反转、反转给谁以及在什么时候进行控制反转等方面的问题。正在业界为IoC的概念争论不休时,大师级人物Martin Fowler发表了一篇经典文章Inversion of Control Containers and the Dependency Injection pattern为IoC正名,至此,IoC又获得了一个新的名字——依赖注入(Dependency Injection)。
Dependency Injection是依赖注入的意思,也就是将应用系统中的各个类之间的依赖关系先剥离(也就是常说的解耦或者分离),然后在应用系统运行过程中根据应用之间的调用关系再适时地注入到目标系统中。
2)什么是依赖注入
根据上面的说明,相对于IoC 而言,“依赖注入”更加准确地描述了IoC的设计理念。从名字上来直接理解,所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
Computer 与CPU和HardDisk之间为组合关系 |
Computer 与Print之间为聚合关系 |
Computer 与UserInfo之间为“一对一”的关联关系 |
private Printer hpPrinter=null;
private UserInfo oneUserInfo=null;
public Result calculate(Data oneData)
Computer 与Data之间为“依赖”关系 |
}
}
class CPU {
}
class HardDisk {
}
class Printer {
}
class UserInfo {
}
【例1-2】 中给出了计算机Computer类与其他各个类之间的各种关系的示例。在传统的应用开发中,需要开发者自己在Computer类中分别创建出各个依赖的目标类的对象实例,如CPU和Printer类对象等,这样将使得Computer类与它所依赖的各个目标类之间产生紧密耦合关系。
3)IoC和DI的本质都是改变依赖关系
组件类和组件类之间的关系依赖由原来的依赖“目标组件”改变为现在的依赖于“IoC容器”。为什么要进行如此的改变?
(1)为什么不应该直接依赖应用系统中的“目标组件”?
依赖在应用系统中是客观存在的,如果应用系统中不存在依赖关系,就意味着应用系统是由各个相互孤立的模块或者组件所构成,这是无法构成一个相互协作和互相配合的有机整体的。
问题是应该依赖谁? 根据Spring框架中的 IoC的设计原理,应用系统中的某个组件类应该依赖所在的上层容器而不要直接依赖目标组件类。主要是由于目标组件类有可能会随着应用系统的需求变化而经常会发生改变和调整,开发者当然也不希望在应用系统中由于某个“方面”发生改变而相关联的各个组件类也必须随之改变!J2EE平台中倡导多层架构中分层的目的也就是希望能够取得良好的隔离效果。
(2)为什么可以依赖于“IoC容器(Spring框架)”?
由于容器相对于应用系统本身而言应该是相对稳定的,不会频繁发生改变(当然,Spring框架本身也会发生升级改变)。这样,也就达到了将应用系统中的“可变”和“不变”部分相互分离的目的。
3.在Spring框架中提出“依赖注入”的设计理念
1)主要目的
软件系统开发中的各种理论、思想包括软件工程等都一直在提倡“软件重用”,但问题是如何能够重用?以及采用什么样的具体实现方法? Spring框架中所提出的“依赖注入”的设计理念为“软件重用”的真正实现带来了可操作的实现方法。
依赖注入的目标并非为软件系统带来更多的功能,应用它的目的是为了提升“组件重用”的概率,同时也为应用系统搭建出一个更加灵活的、可扩展的平台。因为,现在的企业级应用系统的开发更加注重系统的安全性、稳定性、可扩展性和可移植性等目标。
2)应用依赖注入的设计理念在系统架构设计方面所产生的效果
提高了组件的可移植性和可重用度,依赖注入机制减轻了组件之间的依赖关系,因为目标对象的创建并不是在源组件类中直接以编码方式产生的,这也是遵守J2EE平台倡导的“松耦合”的系统开发要求的。
3)应用依赖注入的设计理念在系统开发实现方面所产生的效果
能够更简洁地编程应用J2EE平台中的各种复杂的技术实现,并使应用系统具有良好的可扩展性和灵活性。
下面通过一个在应用系统的持久层开发实现中DAO组件中应用DataSource实现数据库连接的示例,来说明Spring框架中的依赖注入是如何简化系统开发实现的。
1-3 某个DAO组件获得DataSource对象从而获得数据库连接对象的示例。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="dataSource"class=" org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>com.microsoft.jdbc.sqlserver.SQLServerDriver</value>
BasicDataSource是Apache的DBCP数据库连接池的实现 |
<property name="url">
<value>
jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=
定义出目标数据库的连接参数及账号 |
</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value>1234</value>
定义出目标DAO组件对象 |
</bean&g