IoC - Castle Windsor - 扩展container 2.1
当向Windsor容器添加一个组件时,MicroKernel先创建一个ComponentModel对象,用于描述组件信息,然后使用一系列的contributor进行处理,包括探测组件的依赖关系等信息。例如ConstructorDependenciesModelInspector收集public类型的构造器以及其依赖的组件等信息,添加到ComponentModel对象上,而LifestyleModelInspector则检查组件是否有实现特定的生命周期控制接口等
组件注册过程中使用IHandler接口进行处理,如果windsor能够处理组件依赖的对象、组件(比如windsor已经知道如何处理全部的构造函数参数,以便使用它们来构造这个组件的实例对象),则该组件成为可请求状态,表示客户端代码可以通过容器请求该组件的实例对象了;否则这个组件被添加到一个列表中,等待相关的依赖被设置好之后,再将其改为可请求状态
假设我们想自己实现一个IStartable的facility,当windsor容器创建的对象属于IStartable类型后,立即调用接口的Start方法
我们的测试项目中引用的命名空间入下:
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
这一代码,windsor容器就会创建一个MyTask的实例对象,并调用其Start方法,在Console窗口输出一条信息了
参考:Introducing Castle - Part I
组件注册过程中使用IHandler接口进行处理,如果windsor能够处理组件依赖的对象、组件(比如windsor已经知道如何处理全部的构造函数参数,以便使用它们来构造这个组件的实例对象),则该组件成为可请求状态,表示客户端代码可以通过容器请求该组件的实例对象了;否则这个组件被添加到一个列表中,等待相关的依赖被设置好之后,再将其改为可请求状态
假设我们想自己实现一个IStartable的facility,当windsor容器创建的对象属于IStartable类型后,立即调用接口的Start方法
我们的测试项目中引用的命名空间入下:
using System; using System.Collections; using Castle.Core; using Castle.Core.Configuration; using Castle.MicroKernel; using Castle.MicroKernel.LifecycleConcerns; using Castle.MicroKernel.ModelBuilder; using Castle.Windsor; using Castle.Windsor.Configuration.Interpreters;IStartable接口以及测试用的一个实现如下:
public interface IStartable { void Start(); } public class MyTask : IStartable { public void Start() { Console.WriteLine("I have been started~"); } }接下来facility的实现代码如下,大部分处理参考注释即可明白:
public class StartableFacility : IFacility { //保存等待解决依赖关系的组件,该StartableFacility为单例 //因此非static的数组就可以保持所有的等待依赖组件了 private ArrayList _waitList = new ArrayList(); private IKernel _kernel; //Facility初始化时执行的方法 public void Init(IKernel kernel, IConfiguration facilityConfig) { _kernel = kernel; //我们添加一个contributor,用于检测组件是否实现了IStartable接口 //如果实现了这个接口,则将使用这个contributor来添加我们需要的处理 _kernel.ComponentModelBuilder.AddContributor(new StartableInspector()); //每一个组件注册完成都会调用这个事件处理 _kernel.ComponentRegistered += new ComponentDataDelegate(OnComponentRegistered); } //Facility终止时执行的方法,示例中我们不需要处理什么 public void Terminate() { } private void OnComponentRegistered(String key, IHandler handler) { bool startable = (bool) handler.ComponentModel.ExtendedProperties["startable"]; if (startable) { //组件注册完成时,如果其状态为HandlerState.WaitingDependency //我们将其添加到等待列表中 //每一个组件注册完成都会执行该方法,因此如果其依赖的组件已经注册完成 //则我们在后面的CheckWaitingList方法中会将等待依赖的组件设置为ok的状态 if (handler.CurrentState == HandlerState.WaitingDependency) _waitList.Add(handler); else Start(key); //使用windsor请求一个该组件的实例对象 } CheckWaitingList(); } private void Start(string key) { //MicroKernel将创建该组件的一个实例对象 object instance = _kernel[key]; } private void CheckWaitingList() { IHandler[] handlers = (IHandler[])_waitList.ToArray(typeof(IHandler)); foreach (IHandler handler in handlers) { if (handler.CurrentState == HandlerState.Valid) { Start(handler.ComponentModel.Name); _waitList.Remove(handler); } } } } //用于检测组件是否实现了IStartable接口的inspector public class StartableInspector : IContributeComponentModelConstruction { public void ProcessModel(IKernel kernel, ComponentModel model) { bool startable = typeof(IStartable).IsAssignableFrom(model.Implementation); model.ExtendedProperties["startable"] = startable; if (startable) //如果实现了IStartable接口,则添加一个lifestyle step model.LifecycleSteps.Add( LifecycleStepType.Commission, new StartableConcern()); } private class StartableConcern : ILifecycleConcern { public void Apply(ComponentModel model, object component) { //我们在这里实现IStartable接口的处理,调用其Start方法 (component as IStartable).Start(); } } }配置示例如下:
<configuration> <configSections> <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" /> </configSections> <castle> <facilities> <facility id="startable" type="Windsor.Test.StartableFacility, Windsor.Test" /> </facilities> <components> <component id="my.task" service="Windsor.Test.IStartable, Windsor.Test" type="Windsor.Test.MyTask, Windsor.Test" /> </components> </castle> </configuration>这样在程序中,我们只需要执行
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
这一代码,windsor容器就会创建一个MyTask的实例对象,并调用其Start方法,在Console窗口输出一条信息了
参考:Introducing Castle - Part I