Richie

Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?

IoC - Castle Windsor - 扩展container 2.1

当向Windsor容器添加一个组件时,MicroKernel先创建一个ComponentModel对象,用于描述组件信息,然后使用一系列的contributor进行处理,包括探测组件的依赖关系等信息。例如ConstructorDependenciesModelInspector收集public类型的构造器以及其依赖的组件等信息,添加到ComponentModel对象上,而LifestyleModelInspector则检查组件是否有实现特定的生命周期控制接口等
    
组件注册过程中使用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

posted on 2010-03-30 22:15 riccc 阅读(...) 评论(...) 编辑 收藏

导航

News