《Spring揭秘》读书笔记-第二章IoC的基本概念

理念就是让别人为你服务,中文名控制反转,也叫依赖注入DI

public class FXNewsProvider

{

  private IFXNewsListener newsListener;

  private IFXNewsPersister newPersistener;

  public void getAndPersistNews()

{

String[] newsIds = newsListener.getAvailableNewsIds();

if(ArrayUtils.isEmpty(newsIds))

{
   return;
} 

for(String newsId : newsIds)

{ FXNewsBean newsBean = newsListener.getNewsByPK(newsId); 

newPersistener.persistNews(newsBean);

newsListener.postProcessIfNecessary(newsId);

}

}

}

 假设这个类用来处理新闻,

IFXNewsListener 用来获取新闻,

IFXNewsPersister   用来把获取的新闻持久化

当我们需要获取不同的新闻源,比如道琼斯的新闻时,我们会写一个 DowJonesNewsListener 类和 DowJonesNewsPersister 类,然后实例化

public FXNewsProvider()

{

newsListener = new DowJonesNewsListener();

newPersistener = new DowJonesNewsPersister();

}

 

如果我们依赖于某个类或服务,最简单而有效的方式就是直接

在类的构造函数中新建相应的依赖类。

注意看, ,我们都是自己主动地去获

取依赖的对象!

可是回头想想,我们自己每次用到什么依赖对象都要主动地去获取,这是否真的必要?我们最终

所要做的,其实就是直接调用依赖对象所提供的某项服务而已

能不能我们用的时候自动送过来呢?

。现在是用什么,让别人直接送过来就成。所以,简单点儿说, IoC 的理念就是,

让别人为你服务!在图 2-1 中,也就是让 IoC Service Provider 来为你服务!

这里,被注入对象就是 FXNewsProvider ,被依赖于对象 IFXNewsListener  IFXNewsPersister  

通常情况下,被注入对象会直接依赖于被依赖对象。但是,在 IoC 的场景中,二者之间通过 IoC Service

Provider 来打交道,所有的被注入对象和依赖对象现在由 IoC Service Provider 统一管理。被注入对象需要

什么,直接跟 IoC Service Provider 招呼一声,后者就会把相应的被依赖对象注入到被注入对象中,从而

达到 IoC Service Provider 为被注入对象服务的目的。 IoC Service Provider 在这里就是通常的 IoC 容器所充

当的角色。从被注入对象的角度看,与之前直接寻求依赖对象相比,依赖对象的取得方式发生了反转,

控制也从被注入对象转到了 IoC Service Provider 那里

这里我们想知道的是?怎么跟 IoC Service Provider 打招呼

 IoC 模式中,被注入对象又是通过哪些方式来通知 IoC Service Provider 为其提供适当服务的呢?三种打招呼的方式

,即构造方法注入( constructor

injection )、 setter 方法注入( setter injection )以及接口注入( interface injection )。

构造方法注入:

public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister)

{

this.newsListener = newsListner;

this.newPersistener = newsPersister; }

 

 

IoC Service Provider 会检查被注入对象的构造方法,取得它所需要的依赖对象列表,进而为其注

入相应的对象。

setter方法注入

public class FXNewsProvider

{

private IFXNewsListener newsListener;

private IFXNewsPersister newPersistener;

public IFXNewsListener getNewsListener() {

return newsListener;

}

public void setNewsListener(IFXNewsListener newsListener) {

this.newsListener = newsListener;

}

public IFXNewsPersister getNewPersistener() {

return newPersistener;

}

public void setNewPersistener(IFXNewsPersister newPersistener) {

this.newPersistener = newPersistener;

}

}

 

 

外界就可以通过调用 setNewsListener  setNewPersistener 方法为 FXNewsProvider 

象注入所依赖的对象了。

接口注入,这个基本不用了。

接口注入 。从注入方式的使用上来说,接口注入是现在不甚提倡的一种方式,基本处于”退

役状态”。因为它强制被注入对象实现不必要的接口,带有侵入性。而构造方法注入和 setter

方法注入则不需要如此。

8

q 构造方法注入。 这种注入方式的优点就是,对象在构造完成之后,即已进入就绪状态,可以 9

马上使用。缺点就是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反

射构造对象的时候,对相同类型的参数的处理会比较困难,维护和使用上也比较麻烦。而且

 Java 中,构造方法无法被继承,无法设置默认值。对于非必须的依赖处理,可能需要引入多

个构造方法,而参数数量的变动可能造成维护上的不便。

10

q setter 方法注入 。因为方法可以命名,所以 setter 方法注入在描述性上要比构造方法注入好一些。 11

另外, setter 方法可以被继承,允许设置默认值,而且有良好的 IDE 支持。缺点当然就是对象无

法在构造完成后马上进入就绪状态。 12

综上所述,构造方法注入和 setter 方法注入因为其侵入性较弱,且易于理解和使用,所以是现在使

用最多的注入方式;而接口注入因为侵入性较强,近年来已经不流行了。

回到开头的代码

public FXNewsProvider()

{

newsListener = new DowJonesNewsListener();

newPersistener = new DowJonesNewsPersister();

}

 

 

由于这里已经写死了,所以当我们添加了一个新的新闻源,比如M4网站的时候,这个对象不能用了,我们要新写一个 M4 NewsProvider 的类,然后新写新闻获取类,然后重新实现。

而使用了IoC之后,

FXNewsProvider dowJonesNewsProvider =

new FXNewsProvider(new DowJonesNewsListener(),new DowJonesNewsPersister());

FXNewsPrivider marketWin24NewsProvider =

new FXNewsProvider(new MarketWin24NewsListener(),new DowJonesNewsPersister());

 

 

我们只要实现一个 MarketWin24NewsListener 雷就可以,而且 FXNewsProvider 可以重用。

而且使用了IoC之后,单元测试变得简单,我们只有写一个Mock NewsPersister 就可以来测试了。

comments powered by Disqus