1.
控制反转
(Inversion of Control)
与依赖注入
(Dependency Injection)
控制反转即
IoC (Inversion of Control)
,它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
IoC
是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:
<1>
依赖查找(
Dependency Lookup
):容器提供回调接口和上下文环境给组件。
EJB
和
Apache Avalon
都使用这种方式。
<2>
依赖注入(
Dependency Injection
):组件不做定位查询,只提供普通的
Java
方法让容器去决定依赖关系。后者是时下最流行的
IoC
类型,其又有接口注入(
Interface Injection
),设值注入(
Setter Injection
)和构造子注入(
Constructor Injection
)三种方式。
图
1
控制反转概念结构
依赖注入之所以更流行是因为它是一种更可取的方式:让容器全权负责依赖查询,受管组件只需要暴露
JavaBean
的
setter
方法或者带参数的构造子或者接口,使容器可以在初始化时组装对象的依赖关系。其与依赖查找方式相比,主要优势为:
<1>
查找定位操作与应用代码完全无关。
<2>
不依赖于容器的
API
,可以很容易地在任何容器以外使用应用对象。
<3>
不需要特殊的接口,绝大多数对象可以做到完全不必依赖容器。
2.
好莱坞原则
IoC
体现了好莱坞原则,即“不要打电话过来,我们会打给你”。第一次遇到好莱坞原则是在了解模板方法
(Template Mathod)
模式的时候,模板方法模式的核心是,基类(抽象类)定义了算法的骨架,而将一些步骤延迟到子类中。
现在来考虑
IoC
的实现机制,组件定义了整个流程框架,而其中的一些业务逻辑的实现要借助于其他业务对象的加入,它们可以通过两种方式参与到业务流程中,一种是依赖查找(
Dependency Lookup
),类似与
JDNI
的实现,通过
JNDI
来找到相应的业务对象(代码
1
),另一种是依赖注入,通过
IoC
容器将业务对象注入到组件中。
3.
依赖查找(
Dependency Lookup
)
public class MyBusniessObject{
private DataSource ds;
private MyCollaborator myCollaborator;
public MyBusnissObject(){
Context ctx = null;
try{
ctx = new InitialContext();
ds = (DataSource) ctx.lookup(“java:comp/env/dataSourceName”);
myCollaborator =
(MyCollaborator) ctx.lookup(“java:comp/env/myCollaboratorName”);
}……
|
@H_913_301@
依赖查找的主要问题是,这段代码必须依赖于
JNDI
环境,所以它不能在应用服务器之外运行,并且如果要用别的方式取代
JNDI
来查找资源和协作对象,就必须把
JNDI
代码抽出来重构到一个策略方法中去。
4.
依赖注入(
Dependency Injection
)
下面分别演示
3
中注入机制。
package
com.zj.ioc.di;
public
class
Content {
public
void
BusniessContent(){
System.
out
.println(
"do business"
);
}
public
void
AnotherBusniessContent(){
System.
out
.println(
"do another business"
);
}
}
|
@H_913_301@
MyBusniess
类展示了一个业务组件,它的实现需要对象
Content
的注入。代码
3
,代码
4
,代码
5
,
6
分别演示构造子注入(
Constructor Injection
),设值注入(
Setter Injection
)和接口注入(
Interface Injection
)三种方式。
package
com.zj.ioc.di.ctor;
import
com.zj.ioc.di.Content;
public
class
MyBusiness {
private
Content
myContent
;
public
MyBusiness(Content content) {
myContent
= content;
}
public
void
doBusiness(){
myContent
.BusniessContent();
}
public
void
doAnotherBusiness(){
myContent
.AnotherBusniessContent();
}
}
|
@H_913_301@
package
com.zj.ioc.di.set;
import
com.zj.ioc.di.Content;
public
class
MyBusiness {
private
Content
myContent
;
public
void
setContent(Content content) {
myContent
= content;
}
public
void
doBusiness(){
myContent
.BusniessContent();
}
public
void
doAnotherBusiness(){
myContent
.AnotherBusniessContent();
}
}
|
@H_913_301@
package
com.zj.ioc.di.iface;
import
com.zj.ioc.di.Content;
public
interface
InContent {
void
createContent(Content content);
}
|
@H_913_301@
package
com.zj.ioc.di.iface;
import
com.zj.ioc.di.Content;
public
class
MyBusiness
implements
InContent{
private
Content
myContent
;
public
void
createContent(Content content) {
myContent
= content;
}
public
void
doBusniess(){
myContent
.BusniessContent();
}
public
void
doAnotherBusniess(){
myContent
.AnotherBusniessContent();
}
}
|
@H_913_301@
5.
依赖拖拽
(Dependency Pull)
最后需要介绍的是依赖拖拽,注入的对象如何与组件发生联系,这个过程就是通过依赖拖拽实现
。
public static void main(String[] args) throws Exception{
//get the bean factory
beanfactory factory = getbeanfactory();
MessageRender mr = (MessageRender) factory.getBean(“renderer”);
mr.render();
}
|
@H_913_301@