控制反转(IoC)与依赖注入(DI)

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 )三种方式。
控制反转概念结构
依赖注入之所以更流行是因为它是一种更可取的方式:让容器全权负责依赖查询,受管组件只需要暴露 JavaBean setter 方法或者带参数的构造子或者接口,使容器可以在初始化时组装对象的依赖关系。其与依赖查找方式相比,主要优势为: <1> 查找定位操作与应用代码完全无关。 <2> 不依赖于容器的 API ,可以很容易地在任何容器以外使用应用对象。 <3> 不需要特殊的接口,绝大多数对象可以做到完全不必依赖容器。
 
2. 好莱坞原则
IoC 体现了好莱坞原则,即“不要打电话过来,我们会打给你”。第一次遇到好莱坞原则是在了解模板方法 (Template Mathod) 模式的时候,模板方法模式的核心是,基类(抽象类)定义了算法的骨架,而将一些步骤延迟到子类中。
模板方法模式类图
 
现在来考虑 IoC 的实现机制,组件定义了整个流程框架,而其中的一些业务逻辑的实现要借助于其他业务对象的加入,它们可以通过两种方式参与到业务流程中,一种是依赖查找( Dependency Lookup ),类似与 JDNI 的实现,通过 JNDI 来找到相应的业务对象(代码 1 ),另一种是依赖注入,通过 IoC 容器将业务对象注入到组件中。
 
3.  依赖查找( Dependency Lookup
下面代码展示了基于 JNDI 实现的依赖查找机制。
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”);
    }……
代码 1 依赖查找( Dependency Lookup )代码实现
依赖查找的主要问题是,这段代码必须依赖于 JNDI 环境,所以它不能在应用服务器之外运行,并且如果要用别的方式取代 JNDI 来查找资源和协作对象,就必须把 JNDI 代码抽出来重构到一个策略方法中去。
 
4.  依赖注入( Dependency Injection
依赖注入的基本原则是:应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由 IoC 容器负责,“查找资源”的逻辑应该从应用组件的代码中抽取出来,交给 IoC 容器负责。
下面分别演示 3 中注入机制。
代码 待注入的业务对象 Content.java
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" );
    }
}
MyBusniess 类展示了一个业务组件,它的实现需要对象 Content 的注入。代码 3 ,代码 4 ,代码 5 6 分别演示构造子注入( Constructor Injection ),设值注入( Setter Injection )和接口注入( Interface Injection )三种方式。
 
代码 3 构造子注入( Constructor Injection MyBusiness.java
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();
    }
}
 
代码 4 设值注入( Setter Injection  MyBusiness.java
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();
    }
}
 
代码 设置注入接口 InContent.java
package  com.zj.ioc.di.iface;
import  com.zj.ioc.di.Content;
 
public   interface  InContent {
     void  createContent(Content content);
}
 
代码 6 接口注入( Interface Injection MyBusiness.java
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();
    }
}
 
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();
}
而通常 对注入对象 的配置可以通过一个 xml 文件完成。
使用这种方式对对象进行集中管理,使用依赖拖拽与依赖查找本质的区别是,依赖查找是在业务组件代码中进行的,而不是从一个集中的注册处,特定的地点执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值