Castle IOC是Castle的核心和灵魂。有一句话是这么说的,如果要理解castle和spring这样的框架,必须首先理解其IOC。当然,如果停留在使用层次那就不需要了。本章帮你一起揭密Castle IOC本质。
DI和IOC是一直很流行的架构设计思想和方法,IOC是将对象内部的依赖解藕 将原先内部的控制反转给了类之外 又称Dependence Injection 。IOC或DI的核心思想在于提供一个更加简单的机制来规定组件之间的依赖关系(一般涉及到对象的合作),并且在它们生命周期中对依赖关系进行管理。 IOC提供了这样的服务,使一个组件能够在它的生命周期中访问它的依赖和服务。总的来说,IOC能够被分解为两种字类型:依赖注入和依赖查找。从这个意义上来说,当我们谈及DI的时候总是在谈IOC,但是当说到IOC的时候却不一定涉及DI. 需要进一步清楚知道他们的原理和理论请参考其它文章。
1. IOC生命周期
a) Castle.Core.LifestyleType
这里我们关注下列几个值
另外pooled是transient的优化,我估计是小规模的instance 复用。介于singleton和transient之间。
生命周期值可以配置为声明式attribute和配置文件中,无论哪种其原理都是一样的,最终都要回到reflection调用。
两种调用方式示例
基于配置:
1: <component id="GlQuoteCalculator"
2: service="Aspen.Apt.Casualty.BLL.BusinessFacade.GlQuoteCalculator,Aspen.Apt.Casualty.BLL"
3: type="Aspen.Apt.Casualty.BLL.BusinessFacade.GlQuoteCalculator,Aspen.Apt.Casualty.BLL" lifestyle="transient" />
属性声明:
1: [Transactional]
2:
3: [Singleton]
4:
5: public partial class GlQuoteManager : QuoteManagerBase
为了配置为attribute,castle.core定义如下Attribute
customerTypeAttribute通过传入一个自定义实现的type实现对LifestyleType.Custom的扩充。pooled定义了pool的initial size和max size,当然设置attribute的时候可以传入修过. 这里的castleComponentAttribute通过传入key,type和lifestyleType进行批量注册component的lifestyle。这个后面再详细讨论。
2. IOC注入方式
l .基于方法的(Method-based Ioc,Type-0) 这种方式很简单,就是提供一方法,将依赖的类型的在使用的时候(客户端)传入。某些时候这一方法正式客户端所消费的方法。代码略
l 基于接口的(Interface-based Ioc,Type-1) 这种方式很简单,但具备侵略性
1: public class Sport {
2: private InterfaceBall ball; //InterfaceBall是定义的接口
3: public void init() {
4: //Basketball实现了InterfaceBall接口
5: ball = (InterfaceBall) Class.forName("Basketball").newInstance();
6: }
7: }
上面的代码中,Sport依赖于InterfaceBall的实现,如何获得InterfaceBall实现类的实例?传统的方法是在代码中创建InterfaceBall实现类的实例,并将起赋予ball。而这样一来,Sport在编译期即依赖于InterfaceBall的实现。为了将调用者和实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文档中设定的实现类的类名,动态加载实现类,并通过InterfaceBall强制转型后为Sport所用。这就是接口注入的一个最原始的雏形。而对于一个Type1型IOC容器而言,加载接口实现并创建其实例的工作由容器完成,如J2EE研发中常用Context.lookup(ServletContext.getXXX),都是Type1型IOC的表现形式。 Apache Avalon是个典型的Type1型IOC容器。
l 基于设值的(Setter-based Ioc,Type-2) 基于Setter的依赖注入是最佳选择,因为它在非IoC的设置下对你的代码 影响最小。Spring大量使用了此方式,castle也支持此方式。详细后面分解
l 基于构造的(Construtor-based Ioc,Type-3) 当你需要确认依赖关系将被传递给组件的时候,是一个不错的选择。但是要记住很多容器为这种情况提供了它们自己的基于Setter依赖注入的机制。castle支持此方式。详细后面分解
关于IOC注入方式的理论就不讲述了,请参考其它文章。
附:几种IOC优缺点比较
几种依赖注入模式的对比总结
接口注入模式因为具备侵入性,他需要组件必须和特定的接口相关联,因此并不被看好,实际使用有限。
Type2 构造子注入的优势:
1、“在构造期即创建一个完整、合法的对象”,对于这条设计原则,Type2无疑是最好的响应者。
2、避免了繁琐的setter方法的编写,任何依赖关系均在构造函数中设定,依赖关系集中呈现,更加易读。
3、由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处相对“不变”的稳定状态,无需担心上层代码在调用 过程中执行setter方法对组件依赖关系产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
4、同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的层次清楚性提供了确保。
5、通过构造子注入,意味着我们能够在构造函数中决定依赖关系的注入顺序,对于一个大量依赖外部服务的组件而言,依赖关系的获得顺序可能很重要,比如某个依赖关系注入的先决条件是组件的DataSource及相关资源已被设定。
Type3设值注入的优势
1、对于习惯了传统JavaBean研发的程式员而言,通过setter方法设定依赖关系显得更加直观,更加自然。
2、假如依赖关系(或继承关系)较为复杂,那么Type2模式的构造函数也会相当庞大(我们需要在构造函数中设定任何依赖关系),此时Type3模式往往更为简洁。
3、对于某些第三方类库而言,可能需要我们的组件必须提供一个默认的构造函数(如Struts中的Action),此时Type2类型的依赖注入机制就体现出其局限性,难以完成我们期望的功能。
可见,Type2和Type3模式各有千秋,而Spring、PicoContainer都对Type2和Type3类型的依赖注入机制提供了 良好支持。这也就为我们提供了更多的选择余地。理论上,以Type2类型为主,辅之以Type3类型机制作为补充,能够达到最好的依赖注入效果,但是对于基于Spring Framework研发的应用而言,Type3使用更加广泛。
未完,待续。。。