本文是王福强所著<<spring揭秘>>一书的读书笔记

ioc的基本概念

一个例子

我们看下面这个类,getAndPersistNews方法干了四件事

1 通过newsListener获得所有的新闻id;

2 通过newsListener,用新闻id获得新闻实体

3 用newPersistener存储新闻实体

4 再使用newsListener发布新闻

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);
    }

  }
}  

但是newsListener与newPersistener到底从什么地方来呢?

一般情况下或者说我们自己写代码的时候一般在FXNewsProvider的构造方法里生成newsListener与newPersistener。代码如下:

public FXNewsProvider()  {
  newsListener   = new DowJonesNewsListener();
  newPersistener = new DowJonesNewsPersister();
}  

我们分析一下上面的代码,如果对照我们现实生活,那就是我们在造房子的同时自己手工造出(通过new方式)家具。

当然还有可能,你可以去工厂,让他们给你生产。





从代码角度来说,上面的没有问题,还很简洁。

可是,之前是用的一家公司(例如新华社)提供的IFXNewsListener,IFXNewsPersister。如果我想用另一家公司(例如法新社)的IFXNewsListener,IFXNewsPersister怎么办?

方法1 新建一个类继承FXNewsProvider,在FXNewsProvider2的构造方法里使用法新社的IFXNewsListener,IFXNewsPersister,然后getAndPersistNews方法就引用父类的即可。

方法2 重新写一个类似的类,如FXNewsProvider2.....

之前的代码,我们可以理解为是FXNewsProvider自己去取所依赖的组件,那么一旦使用新的组件,我们的更新就会比较麻烦。





那么如果把主动的"取",改为被动地"接受"呢?

构造方法如下:

public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister)  {
  this.newsListener   = newsListner;
  this.newPersistener = newsPersister;
}
//使用DowJones家的新闻
FXNewsProvider dowJonesNewsProvider =
new FXNewsProvider(new DowJonesNewsListener(),new DowJonesNewsPersister());
//MarketWin24家的新闻
FXNewsPrivider marketWin24NewsProvider =
new FXNewsProvider(new MarketWin24NewsListener(),new DowJonesNewsPersister());

这样一来,你想用谁的就用谁的。因为是别人给你推送(注入)过来的嘛。

注入方式

有三种,接口注入,构造方法注入,setter方法注入。

构造方法注入上面已经介绍了。

接口注入现在基本已经不用了,大家不用理会。

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;
  }
} 

看上去太简单了,不是吗。

掌管大局的IoC Service Provider

我们第二章说了,让别人来来给我"推送"我所需要的组件。

那么这个别人到底是谁?

别人就是IoC Service Provider。

IoC Service Provider在这里是一个抽象出来的概念,它可以指代任何将IoC场景中的业务对象绑定到一起的实现方式。它可以是一段代码,也可以是一组相关的类,甚至可以是比较通用的IoC框架或者IoC容器实现。

我们可以认为下面这4行代码就是IoC Service Provider,因为它完成了任务----将IoC场景中的业务对象绑定到一起

IFXNewsListener newsListener = new DowJonesNewsListener();
IFXNewsPersister newsPersister = new DowJonesNewsPersister();
FXNewsProvider newsProvider = new FXNewsProvider(newsListener,newsPersister);
newsProvider.getAndPersistNews();  

IoC Service Provider的职责

1 生产对象

2 绑定对象间的依赖关系。

如何管理依赖关系

硬编码

IoContainer container = ...;
container.register(FXNewsProvider.class,new FXNewsProvider());
container.register(IFXNewsListener.class,new DowJonesNewsListener());
container.register(IFXNewsPersister.class,new DowJonesNewsPersister()); 

//setRelation这个方法是我自己写的 sping不会这么干的 但是大概能说明问题
container.setRelation(FXNewsProvider.class,newsListener,IFXNewsListener.class);
container.setRelation(FXNewsProvider.class,newPersistener,IFXNewsPersister.class);

FXNewsProvider newsProvider = (FXNewsProvider)container.get(FXNewsProvider.class);
newProvider.getAndPersistNews(); 

在书的第四章,有一个硬编码的列子:

public static void main(String[] args)  {
  DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
  BeanFactory container = (BeanFactory)bindViaCode(beanRegistry);
  FXNewsProvider newsProvider =
  (FXNewsProvider)container.getBean("djNewsProvider");
  newsProvider.getAndPersistNews();
} 

public static BeanFactory bindViaCode(BeanDefinitionRegistry registry) {
    AbstractBeanDefinition newsProvider =
    new RootBeanDefinition(FXNewsProvider.class,true);
    AbstractBeanDefinition newsListener =
    new RootBeanDefinition(DowJonesNewsListener.class,true);
    AbstractBeanDefinition newsPersister =
    new RootBeanDefinition(DowJonesNewsPersister.class,true); 

    // 将bean定义注册到容器中
    registry.registerBeanDefinition("djNewsProvider", newsProvider);
    registry.registerBeanDefinition("djListener", newsListener);
    registry.registerBeanDefinition("djPersister", newsPersister); 

    // 指定依赖关系
    // 1. 可以通过构造方法注入方式
    ConstructorArgumentValues argValues = new ConstructorArgumentValues();
    argValues.addIndexedArgumentValue(0, newsListener);
    argValues.addIndexedArgumentValue(1, newsPersister);
    newsProvider.setConstructorArgumentValues(argValues); 

    // 2. 或者通过setter方法注入方式
    MutablePropertyValues propertyValues = new MutablePropertyValues();
    propertyValues.addPropertyValue(new ropertyValue("newsListener",newsListener));
    propertyValues.addPropertyValue(new PropertyValue("newPersistener",newsPersister));
    newsProvider.setPropertyValues(propertyValues);
    // 绑定完成
    return (BeanFactory)registry;
}  

不是很难,大家应该能看懂。

配置文件方式

<bean id="newsProvider" class="..FXNewsProvider">
  <property name="newsListener">
   <ref bean="djNewsListener"/>
  </property>
  <property name="newPersistener">
   <ref bean="djNewsPersister"/>
  </property>
</bean> 

<bean id="djNewsListener"
  class="..impl.DowJonesNewsListener">
</bean>
<bean id="djNewsPersister"
  class="..impl.DowJonesNewsPersister">
</bean>  
...
container.readConfigurationFiles(...);
FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("newsProvider");
newsProvider.getAndPersistNews(); 

元数据方式(注解方式)

这种方式的代表实现是Google Guice。我们可以直接在类中使用元数据信息来标注各个对象之间的依赖关系,然后由Guice框架根据这些注解所提供的信息将这些对象组装后,交给客户端对象使用。

public class FXNewsProvider  {
  private IFXNewsListener  newsListener;
  private IFXNewsPersister newPersistener; 

  @Inject
  public FXNewsProvider(IFXNewsListener listener,IFXNewsPersister persister)    {
    this.newsListener   = listener;
    this.newPersistener = persister;
  } 

}  

通过构造方法上的 @Inject,Guice就知道这个用构造方法注入方式,当然具体注入哪个对象,还需要别的信息,在Guice中是由Module提供的

 public class NewsBindingModule extends AbstractModule  { 

  @Override
  protected void configure() {
   bind(IFXNewsListener.class).to(DowJonesNewsListener.class).in(Scopes.SINGLETON);
   bind(IFXNewsPersister.class).to(DowJonesNewsPersister.class).in(Scopes.SINGLETON);
  } 

}  

最后的使用

Injector injector = Guice.createInjector(new NewsBindingModule());
FXNewsProvider newsProvider = injector.getInstance(FXNewsProvider.class);
newsProvider.getAndPersistNews(); 

感谢glt

spring揭秘 读书笔记 一 IoC初探的更多相关文章

  1. spring揭秘读书笔记----spring的ioc容器之BeanFactory

    spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...

  2. spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...

  3. spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  4. Spring揭秘 读书笔记 三 bean的scope与FactoryBean

    本书可作为王富强所著<<Spring揭秘>>一书的读书笔记  第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...

  5. Spring揭秘读书笔记 八 数据访问异常体系

    这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...

  6. spring揭秘读书笔记----ioc的基本概念

    在看ico概念之前,先想一下我们平常需要依赖某个类时会怎么做? 无非是在要用到的地方写如下代码: Person person = new Person(); //然后就可以用person对象来获取Pe ...

  7. Spring揭秘 读书笔记 五 容器的启动

    Spring的IoC容器所起的作用,就是生产bean,并维持bean间的依赖关系.它会以某种方式加载Configuration Metadata(通常也就是XML格式的配置信息),然后根据这些信息绑定 ...

  8. Spring揭秘 读书笔记 七 BeanFactory的启动分析

    首先,先看我自己画的BeanFactory启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(Stri ...

  9. spring揭秘 读书笔记 六 bean的一生

    我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...

随机推荐

  1. Bootstrap3 栅格系统-Less mixin 和变量

    除了用于快速布局的预定义栅格类,Bootstrap 还包含了一组 Less 变量和 mixin 用于帮你生成简单.语义化的布局. 变量 通过变量来定义列数.槽(gutter)宽.媒体查询阈值(用于确定 ...

  2. ZooKeeper之(一)ZooKeeper是什么

    1.1 产生背景 当今是个分布式.集群.云计算等名词满天飞的时代.造成这种局面的一个重要因素就是,单一机器的处理能力已经不能满足我们的需求,不得不采用由多台机器组成的服务集群.服务集群对外提供服务的过 ...

  3. Android给控件添加触摸回调

    Android给控件添加触摸回调 脑补一个场景,一个页面点击某个按钮会弹出PopupWindow,然后点击PopupWindow以外的任意位置关闭 效果图 实现方法 可以在布局的最外层容器监听触摸事件 ...

  4. 全废话SQL Server统计信息(1)——统计信息简介

    当心空无一物,它便无边无涯.树在.山在.大地在.岁月在.我在.你还要怎样更好的世界?--张晓风<我在> 为什么要写这个内容? 随着工作经历的积累,越来越感觉到,大量的关系型数据库的性能问题 ...

  5. activiti节点跳转

    分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519) activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业 ...

  6. 第三方开源动画库EasyAnimation中一个小bug的修复

    看过iOS动画之旅的都知道,其中在最后提到一个作者写的开源动画库EasyAnimation(以下简称EA). EA对CoreAnimation中的view和layer动画做了更高层次的包装和抽象,使得 ...

  7. JQuery插件使用之Validation 快速完成表单验证的几种方式

    JQuery的Validation插件可以到http://plugins.jquery.com/上去下载.今天来分享一下,关于这个插件的使用. 简易使用 这第一种方式可谓是傻瓜式的使用,我们只需要按照 ...

  8. 安卓Toast自定义及防止重复显示

    Toast是安卓系统中,用户误操作时或某功能执行完毕时,对用户的一种提示,它没有焦点,并在一定时间内会消失,但用户连续误操作(如登录时,密码错误)多次时,则会有多个Toast被创建,系统会把这些toa ...

  9. memcached实战系列(四)memcached stats命令 memcached优化

    memcached提供一系列的命令进行优化的查看,方便我们调整我们的存储策略,查看我们的使用率,内存的使用率以及浪费情况.常用的命令有stats.stats settings.stats items. ...

  10. Android View框架总结(五)View布局流程之Layout

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52216195 View树的Layout流程 View的Layout时序图 View布局 ...