Castle实践1-Castle IOC容器剖析

大家好!本节向大家讲述IOC容器的基本使用方法并来看看他是如何处理的。
     IOC的概念我就不讲了,如果你对这还不够熟悉的话,我推荐你看Inversion of Control Containers and the Dependency Injection pattern。我这里借助hammett的一句话来概括IOC的意义:
one of the uses of inversion of control that solves the loosely coupled problem (or one aspect of it) is by inverting how your class obtains external object references or configuration.用两个字概括-低耦。


1)获取容器
Windsor作为Castle使用IOC容器是建立在MicroKernel的基础上的,用于负责检测类型和类型之间工作依赖性,并提供服务(requirements )或者发生错误时提供预警的机制(fail fast )。
// 建立一个容器
IWindsorContainer container = new WindsorContainer();
// 加入一个组件
container.AddComponent( "newService"typeof(IService), 
                       
typeof(MyService) );
// 获取组件
IService service = (IService)container["newService"];
MyService service 
= (MyService)container["newService"];
// 使用
service.DoSomeService();
上面演示了使用容器的一个简单过程:
首先,我们向容器注册了一个服务接口IService,而MyService是实现了这个接口的一个类,newService是一个key用来标识这个组件,然后通过key,我们可以取得注册的组件,可以直接转为IService接口或者是MyService来使用。
在这里,如果这个Service组件是依赖于其他其他组件的,在其他组件没有加载,换句话就是说“依赖性检查尚未通过”时,就使用的话,会产生Exception的。只有使用的组件的所有依赖性完全满足时,才可以正常使用。
深入分析组件的注册:
Windsor的核心是MicroKernel,组件是交由MicroKernel的ModelBuilder处理的。
找到DefaultComponentModelBuilder类,它实现了IComponentModelBuilder接口,提供默认的组件向容器注册的行为。
IComponentModelBuilder有三个方法BuildModel,AddContributor,RemoveContributor,其中BuildModel按顺序调用Add进来的Contributor对组件进行处理。
所有的Contributor都实现IComponentModelBuilder接口,这个接口只有ProcessModel一个方法,从方法名字中可以很清楚的知道这个接口就是用于处理模块的。
看回DefaultComponentModelBuilder的初始化方法:InitializeContributors(),这里挂接各种Contributor来形成一个处理流来处理组件模块。
protected virtual void InitializeContributors()
{
   
// 处理配置
   AddContributor( new ConfigurationModelInspector() );
   
// 处理生命方式:Undefined,Singleton,Thread,Transient,Pooled,Custom
   AddContributor( new LifestyleModelInspector() );
   
// 处理构造函数依赖
   AddContributor( new ConstructorDependenciesModelInspector() );
   
// 处理属性依赖
   AddContributor( new PropertiesDependenciesModelInspector() );
   
// 处理生命周期,也就是在组件装在,初始化,销毁所出发的行为,分别对应三个接口:IInitializable,ISupportInitialize,IDisposable。你的组件实现了这些接口,容器会自动在不同的生命周期调用他们。
   AddContributor( new LifecycleModelInspector() );
   
// 处理配置文件中的parameters元素内容
   AddContributor( new ConfigurationParametersInspector() );
   
// 处理配置文件中的interceptors元素内容
   AddContributor( new InterceptorInspector() );
}
最后,你可以通过AddContributor或者RemoveContributor来新添对组件的个性化处理。
忘记说了,注册组件的过程就是建立ComponentModel的过程,ComponentModel是组件的“信息库”。
完成注册组件之后,就可以使用组件了,组件由容器创建,而这个创建工作交给ComponentActivator处理,Activator会根据ComponentModel里面的信息对组件进行依赖检查,依赖检查通过后,根据指定的生命方式创建组件(默认是单例),并在创建的时候触发实现了IInitializable和ISupportInitialize的组件行为。对象创建之后就直到销毁,这时候对象实现的IDisposable就被调用了。

2)配置容器
在上面我们获取容器时,是直接将容器实例化的。
IWindsorContainer container = new WindsorContainer();
那么我们如何配置容器呢?
其实直接将容器实例化的时候,容器会自动检查你的AppConfig中的容器配置,如下:
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
   
<configSections>
       
<section name="castle"
         type
="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, 
               Castle.Windsor"
 />
   
</configSections>
   
<castle>
       
<components>
           
<component id="smtpemailsender">
               
<parameters>
                   
<host>localhost</host>
                   
<port>110</port>
               
</parameters>
           
</component>
       
</components>
   
</castle>
</configuration>
当然,你也可以通过其他方式来配置容器:
*指定Xml文件,传入构造器。
*实现接口:IConfigurationStore来自定义配置。
配置容器莫非就是做了两件事情:
一是注册Facility,二是注册Component。
WindsorContainer是MicroKernel的外壳,WindsorContainer包含3个内部属性:

private IKernel _kernel;
private IWindsorContainer _parent;
private IComponentsInstaller _installer; 
WindsorContainer提供对_kernel的初始化,WindsorContainer的配置能力很强,可以实现自己的配置解释语言,也有提供默认的XML的方式:
IConfigurationInterpreter是一个配置解释器接口,它只有一个方法:
void Process(IConfigurationStore store);
方法名称表明是处理IConfigurationStore,而IConfigurationStore提供给_kernel内部使用,也就是_kernel通过此接口获取组件和扩展单元的配置。下面分析一下WindsorContainer处理配置的过程:
// 通过传入xml文件路径来初始化配置
IWindsorContainer container = new WindsorContainer("../MyConfig.xml");
内部是这样处理的:
开始传入xml:
public WindsorContainer(String xmlFile) : this(new XmlInterpreter(xmlFile)) {}

XmlInterpreter是一个IConfigurationInterpreter,接着来看下一步:
public WindsorContainer(IConfigurationInterpreter interpreter) : this()
{
 
if (interpreter == nullthrow new ArgumentNullException("interpreter");
 interpreter.Process(Kernel.ConfigurationStore);
 RunInstaller();
}

再下一步:
public WindsorContainer() : this(new DefaultKernel(), new Installer.DefaultComponentInstaller()) {}

最后一步:
public WindsorContainer(IKernel kernel, IComponentsInstaller installer)
{
 _kernel 
= kernel;
 _kernel.ProxyFactory 
= new Proxy.DefaultProxyFactory();
 _installer 
= installer;
}
跟踪上面的构造过程,可以看到:
_kernel 是一个DefaultKernel
_installer 是一个DefaultComponentInstaller
_parent 是当前容器的父容器
在数据初始化完毕后,调用IConfigurationInterpreter的Process来处理Kernel.ConfigurationStore,此时Kernel.ConfigurationStore是一个DefaultConfigurationStore(在new DefaultKernel()的时候作为一个SubSystem加入到Kernel的SubSystem里面),DefaultConfigurationStore里面就只有两个Dictionary分别用来保存facilities和components。
当前的的IConfigurationInterpreter是一个XmlInterpreter,跟踪到XmlInterpreter的Process处理:
using (Source)
{
 XmlDocument doc 
= new XmlDocument();
 doc.Load(Source.Contents);
 Deserialize(doc.DocumentElement, store);
}

很明显,这里载入xml文件,根据xml里面的配置反序列化把配置内容加入到DefaultConfigurationStore里面的两个Dictionary里面,这样就完成了facilities和components的初始化了。

3)使用容器
容器的使用都是通过:IWindsorContainer 接口的,它提供一系列加载facilities和components的方法。IWindsorContainer把实际的行动交给DefaultKernel处理,而DefaultKernel就调用ComponentModelBuilder来真正BuildModel并引发相应的Event。
同时,IWindsorContainer 也提供一系列释放facilities和components的方法,释放的同时也要检查依赖性,只有别的组件对要释放的组件没有依赖时候才能成功释放。同样真正的释放动作都是交给Kernel处理的。

今次剖析到此结束,如果大家认为哪里说得不是很清楚的,请提宝贵意见。
建议看本文时候,结合我的思路跟踪下源码,才能真正了解Castle的机制。
下篇,我将带大家进入真正的应用,如何使用Facilities,他和Spring的机制有何不同呢?
原文地址:https://www.cnblogs.com/wj/p/179360.html