spring揭秘 读书笔记 一

本文是王福强所著<<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(); 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-24 04:37:50

spring揭秘 读书笔记 一的相关文章

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

本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Provider提供两个功能对象的创建,依赖关系的管理. 只是,IoC容器这个词中,我们还得关注容器二字.它还包括了一些别的功能,例如以下图 Spring提供了两种类型的容器,各自是BeanFactory与ApplicationContext. 它们的差别在于: BeanFactory:对于它所管理的bean,採

spring揭秘 读书笔记 二

本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Provider提供两个功能对象的创建,依赖关系的管理. 不过,IoC容器这个词中,我们还得关注容器二字.它还包含了一些别的功能,如下图 Spring提供了两种类型的容器,分别是BeanFactory与ApplicationContext. 它们的区别在于: BeanFactory:对于它所管理的bean,采取的

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

首先,先看我自己画的BeanFactory启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(String[] args){ BeanFactory factory=new XmlBeanFactory(new ClassPathResource("applicationContext2.xml")); } 我们从这一行代码开始. 关于Resources与ResourcesLoader的资

Asp.Net揭秘读书笔记

Asp.Net揭秘读书笔记 2016年5月16日, 星期一 runat="server"属性代表了一个在服务器端执行的asp.net控件: 如果在webconfig中添加了命名空间,整个项目就可以使用这个类库了 asp控件的textbox举例:<asp:Textbox id="textbox1" runat="server" /> asp:前缀: 指定控件的命名空间 id,所有控件必须有一个唯一的id,可以在代码引用 方法中sende

Spring实战读书笔记(1)

Spring的根本使命是? 简化Java开发 为了降低Java开发的复杂性,Spring采取了哪4种关键策略? 1.基于POJO的轻量级和最小侵入性编程 2.通过依赖注入和面向接口实现松耦合 3.基于切面和惯例进行声明式编程 4.通过切面和模板减少样板式代码 依赖注入与AOP编程 1.如果想对依赖注入有更多的认识,推荐阅读Dhanji R. Prasanna的<Dependency Injection> 2.依赖注入让相互协作的软件组件保持松散耦合,而AOP编程允许你把遍布应用各处的功能分离出

asp.net MVC4 框架揭秘 读书笔记系列2

1.2 MVC 变体 MVC 是一种Pattern 另外一种说法是ParaDigm 范例 模式和范例的区别在于前者可以应用到具体的应用上,而后者则仅仅提供一些指导方针 1.2.1 MVP Model View Presenter 交互图 MVC 模式中元素之间 “混乱”的交互主要体现在允许View 和 Model 绕开Controller进行单独交流,这在MVP 模式中得到了充分解决 PV 模式 (passive View) 解决View很难测试的最好方法是让他无需测试,让UI处理更少逻辑,被动

asp.net MVC4 框架揭秘 读书笔记系列3

IIS/ASP.net管道 本节全部用图形表示便于理解和记忆 1.3.1 IIS5.x与asp.net 1.3.2 IIS 6.0与asp.net 1.3.3 IIS7.0与asp.net 基于IIS6.0与asp.net 双管道设计 基于IIS7.0与asp.net 集成管道设计 1.3.4 asp.net管道

css揭秘读书笔记

currentColor属性让hr和段落相同的颜色: div { color: red; } hr { background: currentColor; /* 一定要设置高度*/ height: 0.1rem; } <div> <p><hr>p里面的hr标签不变色<hr></p> <hr> </div> background-origin:padding-box是背景图片的默认原点,background-position

asp.net MVC4 框架揭秘 读书笔记系列1

1.1 传统MVC 名词解释 Autonomous View. AV. 自制视图 GUI图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面.与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受. SoC seperation of concers 关注点分离(Separation of concerns,SOC)是对只与“特定概念.目标”(关注点)相关联的软件组成部分进行“标识.封装和操纵”