首    页 建模架构 设计模式 培训咨询 jdon框架 论坛

Ioc模式(又称DI:Dependency Injection 依赖注射)

板桥里人 http://www.jdon.com 2004/01/31

  分离关注( Separation of Concerns : SOC)是Ioc模式和AOP产生最原始动力,通过功能分解可得到关注点,这些关注可以是 组件Components, 方面Aspects或服务Services。

  从GoF设计模式中,我们已经习惯一种思维编程方式:Interface Driven Design 接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是接口一定是需要实现的,也就是如下语句迟早要执行:

  AInterface a = new AInterfaceImp();

  AInterfaceImp是接口AInterface的一个子类,Ioc模式可以延缓接口的实现,根据需要实现,有个比喻:接口如同空的模型套,在必要时,需要向模型套注射石膏,这样才能成为一个模型实体,因此,我们将人为控制接口的实现成为“注射”。

  Ioc英文为 Inversion of Control,即反转模式,这里有著名的好莱坞理论:你呆着别动,到时我会找你。后被Martin Fowler改名为 Dependency Injection 依赖注射,也就是将类之间的关系通过第三方进行注射,不需要类自己去解决调用关系。

  其实Ioc模式也是解决调用者和被调用者之间的一种关系,上述AInterface实现语句表明当前是在调用被调用者AInterfaceImp,由于被调用者名称写入了调用者的代码中,这产生了一个接口实现的原罪:彼此联系,调用者和被调用者有紧密联系,在UML中是用依赖 Dependency 表示。

  但是这种依赖在分离关注的思维下是不可忍耐的,必须切割,实现调用者和被调用者解耦,新的Ioc模式 Dependency Injection 模式由此产生了, Dependency Injection模式是依赖注射的意思,也就是将依赖先剥离,然后在适当时候再注射进入。

Ioc模式(Dependency Injection模式)有三种:

第一种类型 从JNDI或ServiceManager等获得被调用者,这里类似ServiceLocator模式。 1. EJB/J2EE
2. Avalon(Apache的一个复杂使用不多的项目)
第二种类型 使用JavaBeans的setter方法 1. Spring Framework,
2. WebWork/XWork
第三种类型 在构造方法中实现依赖 1. PicoContainer,
2. HiveMind

  有过EJB开发经验的人都知道,每个EJB的调用都需要通过JNDI寻找到工厂性质的Home接口,在我的教程EJB是什么章节中,我也是从依赖和工厂模式角度来阐述EJB的使用。

  在通常传统情况下,为了实现调用者和被调用者解耦,分离,一般是通过工厂模式实现的,下面将通过比较工厂模式和Ioc模式不同,加深理解Ioc模式。

工厂模式和Ioc

  假设有两个类B 和 C:B作为调用者,C是被调用者,在B代码中存在对C的调用:

public class B{
   private C comp;
  ......
}

  实现comp实例有两种途径:单态工厂模式和Ioc。

工厂模式实现如下:

public class B{
   private C comp;
  private final static MyFactory myFactory = MyFactory.getInstance();

  public B(){
    this.comp = myFactory.createInstanceOfC();

  }
   public void someMethod(){
    this.comp.sayHello();
  }
  ......
}

特点:

  • 每次运行时,MyFactory可根据配置文件XML中定义的C子类实现,通过createInstanceOfC()生成C的具体实例。

使用Ioc依赖性注射( Dependency Injection )实现Picocontainer如下,B类如同通常POJO类,如下:

public class B{
   private C comp;
  public B(C comp){
    this.comp = comp;
   }
   public void someMethod(){
    this.comp.sayHello();
   }
  ......
}

假设C接口/类有有一个具体实现CImp类。当客户端调用B时,使用下列代码:

public class client{
   public static void main( String[] args ) {
    DefaultPicoContainer container = new DefaultPicoContainer();
    container.registerComponentImplementation(CImp.class);
    container.registerComponentImplementation(B.class);
    B b = (B) container.getComponentInstance(B.class);
    b.someMethod();
   }
}

  因此,当客户端调用B时,分别使用工厂模式和Ioc有不同的特点和区别:

  主要区别体现在B类的代码,如果使用Ioc,在B类代码中将不需要嵌入任何工厂模式等的代码,因为这些工厂模式其实还是与C有些间接的联系,这样,使用Ioc彻底解耦了B和C之间的联系。

  使用Ioc带来的代价是:需要在客户端或其它某处进行B和C之间联系的组装。

  所以,Ioc并没有消除B和C之间这样的联系,只是转移了这种联系。
  这种联系转移实际也是一种分离关注,它的影响巨大,它提供了AOP实现的可能。

Ioc和AOP

  AOP我们已经知道是一种面向切面的编程方式,由于Ioc解放自由了B类,而且可以向B类实现注射C类具体实现,如果把B类想像成运行时的横向动作,无疑注入C类子类就是AOP中的一种Advice,如下图:

  通过下列代码说明如何使用Picocontainer实现AOP,该例程主要实现是记录logger功能,通过Picocontainer可以使用简单一行,使所有的应用类的记录功能激活。

首先编制一个记录接口:

public interface Logging {

  public void enableLogging(Log log);

}

有一个LogSwitcher类,主要用来激活具体应用中的记录功能:

import org.apache.commons.logging.Log;
public class LogSwitcher
{
  protected Log m_log;
  public void enableLogging(Log log) {
    m_log = log;
    m_log.info("Logging Enabled");
  }
}

一般的普通应用JavaBeans都可以继承这个类,假设PicoUserManager是一个用户管理类,代码如下:

public class PicoUserManager extends LogSwitcher
{

  ..... //用户管理功能
}
public class PicoXXXX1Manager extends LogSwitcher
{

  ..... //业务功能
}
public class PicoXXXX2Manager extends LogSwitcher
{

  ..... //业务功能
}

注意LogSwitcher中Log实例是由外界赋予的,也就是说即将被外界注射进入,下面看看使用Picocontainer是如何注射Log的具体实例的。


DefaultPicoContainer container = new DefaultPicoContainer();
container.registerComponentImplementation(PicoUserManager.class);
container.registerComponentImplementation(PicoXXXX1Manager.class);
container.registerComponentImplementation(PicoXXXX2Manager.class);
.....

Logging logging = (Logging) container.getComponentMulticaster();

logging.enableLogging(new SimpleLog("pico"));//激活log

  由上代码可见,通过使用简单一行logging.enableLogging()方法使所有的应用类的记录功能激活。这是不是类似AOP的advice实现?

  总之,使用Ioc模式,可以不管将来具体实现,完全在一个抽象层次进行描述和技术架构,因此,Ioc模式可以为容器、框架之类的软件实现提供了具体的实现手段,属于架构技术中一种重要的模式应用。J道的Jdon框架使用了Ioc模式,JiveJdon3.0是一个IOC/DI成熟应用。

参考资料:

国人最早开源IOC/AOP框架JdonFramework

Inversion of Control Containers and the Dependency Injection pattern

A Brief Introduction to IoC

Ioc容器的革命性优点

Java企业系统架构选择考量

IOC模式的思考和疑问

作者在2004年中国软件技术大会演讲

发表相关讨论...

 

更多依赖注射专题

更多关于IOC讨论

 

 


更多标签...



Jdon框架演示

JiveJdon
源码下载

VIP收费区

历史热点讨论排行榜




google yahoo 新浪ViVi 365Key网摘 天极网摘 CSDN网摘 添加到百度搜藏 POCO网摘





手机 add to google add to yahoo
联系我们 | 关于我们 | 广告联系 | 网站地图 | 设为首页

沪ICP证08026060 如有意见请与我们联系 Powered by JdonFramework
_×
您有新消息