从零开始的实习——Spring——IoC Service Provider

IoC Service Provider的职责

虽然业务对象可以通过IoC方式声明相应的依赖,但是最终仍然需要通过某种角色或者服务将这些相互依赖的对象绑定在一起。
IoC Service Provider在这里是一个抽象出来的概念,甚至可以是比较通过的IoC框架或者IoC容器实现。比如:

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

这段代码可以认为是这个场景中的IoC Service Provider,但是要将系统中的几十个几百个业务对象绑定在一起,采用这种方式显然是不切实际的。
IoC Service Provider的职责有两个:

  • 业务对象的构建管理:在IoC场景中,业务对象无需关心锁依赖的对象如何构建如何取得,但这部分工作始终需要有人来做。所以,IoC Service Provider需要将对象的构建逻辑从客户端对象那里剥离出来,以免这部分逻辑污染业务对象的实现
  • 业务对象间的依赖绑定

IoC Service Provider如何管理对象间的依赖关系

拿酒吧的例子说事,不管是常客还是初次光顾,如果服务生(Ioc Service Provider)连酒都分不清,你能指望他能及时的把酒端给你么?
服务生最终必须知道顾客点的饮品和库存饮品的对应关系,对于IoC Service Provider来说,它也同样需要知道自己所管理和掌握的被注入对象和依赖对象之间的对应关系。
所以这个服务生可以使用如下方法记录被注入对象和依赖对象的关系:

  • 文本文件记录对应信息。
  • XML文件格式来记录对应信息。
  • 通过编写代码的方式来注册这些对应信息。
直接编码方式:

当前大部分IoC容器都应该支持直接编码方式,比如PicoContainer/Spring/Avalon等等。在容器启动之前,我们就可以通过程序编码的方式将被注入对象和依赖对象注册到容器中:

IoContainer container = ...;
container.register(FXNewsProvider.class,new FXNewsProvider());
container.register(IFXNewsListener.class,new DowJonesNewsListener());
...
FXNewsProvider newsProvider = (FXNewsProvider)container.get(FXNewsProvider.class);
newProvider.getAndPersistNews();

如果是接口注入,除了注册相应对象,还要讲注入标志接口与相应的依赖对象绑定一下,才能让容器最终知道是一个什么样的对应关系:

IoContainer container = ...;
container.register(FXNewsProvider.class,new FXNewsProvider());
container.register(IFXNewsListener.class,new DowJonesNewsListener());
...
container.bind(IFXNewsListenerCallable.class, container.get(IFXNewsListener.class));
...
FXNewsProvider newsProvider = (FXNewsProvider)container.get(FXNewsProvider.class);
newProvider.getAndPersistNews();

通过bind方法将“被注入对象”(由IFXNewsListenerCallable家口添加标志)所依赖的对象,绑定为容器中注册过的IFXNewsListener类型的对象实例。

配置文件方式

这是一种较为普遍的依赖注入方式。像普通文件或者XML文件、properties文件等等都可以作为注入依赖的载体:
通过Spring的配置方式来管理FXNewsProvider的依赖注入关系:

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

最后,我们就可以通过"newsProvider"这个名字,从容器中取得已经组装好的FXNewsProvider并直接使用。
从读取配置文件完成对象组装的容器中获取FXNewsProvider并使用:

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,我们指明需要IoC Service Provider通过构造方法注入方式,为FXNewsProvider注入所依赖的对象。至于余下的依赖相关信息,在Guice中是由相应的Module来提供的:
FXNewsProvider所使用的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);
} 
}

通过Module指定进一步的依赖注入相关信息后,我们可以直接从Guice那里取得最终已经注入完毕,并直接可用的对象了。

Injector injector = Guice.createInjector(new NewsBindingModule());
FXNewsProvider newsProvider = injector.getInstance(FXNewsProvider.class);
newsProvider.getAndPersistNews();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值