控制反转和依赖注入(转)

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)模式的时候,模板方法模式的核心是,基类(抽象类)定义了算法的骨架,而将一些步骤延迟到子类中。
 
图2 模板方法模式类图
 
如今来考虑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中注入机制。
代码2 待注入的业务对象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();
    }
}
 
代码5 设置注入接口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)
最后须要介绍的是依赖拖拽,注入的对象如何与组件发生联系,这个过程就是经过依赖拖拽实现。
代码7 依赖拖拽示例
public static void main(String[] args) throws Exception{
//get the bean factory
BeanFactory factory = getBeanFactory();
MessageRender mr = (MessageRender) factory.getBean(“renderer”);
mr.render();
}
而一般对注入对象的配置能够经过一个xml文件完成。
使用这种方式对对象进行集中管理,使用依赖拖拽与依赖查找本质的区别是,依赖查找是在业务组件代码中进行的,而不是从一个集中的注册处,特定的地点执行。
相关文章
相关标签/搜索