Castle IOC容器实践之Startable Facility(二)

摘要:在Castle IOC容器实践之Startable Facility(一)中我们已经学会了如何去使用Startable Facility,本文将在此基础进一步对它的原理做一些分析。

 

主要内容

Startable Facility原理分析

……

 

Castle IOC容器实践之Startable Facility(一)中我们已经看到了如何去使用Startable Facility,本文将对它的原理做一些分析。先看一下接口IStartable,它的实现代码如下:

public interface IStartable
{
    
void Start();

    
void Stop();
}


代码是相当的简单,只有两个方法,分别在组件创建的时候和销毁的时候执行,这就涉及到了组件的生命周期管理。在Windsor中,接口ILifecycleConcern提供特定的组件生命周期管理:

public interface ILifecycleConcern
{
    
void Apply( ComponentModel model, object component );

}


现在我们要实现组件的自动创建和销毁,就需要实现接口ILifecycleConcern,在Startable Facility中分别用两个类来实现,第一个类StartConcern,它判断如果组件实现了接口IStartable,则直接调用它的Start()方法;如果组件是用特性startMethod,则获取并调用具有startMethod特性的方法:

public class StartConcern : ILifecycleConcern
{
    
private static readonly StartConcern _instance = new StartConcern();

    
protected StartConcern()
    
{

    }


    
public static StartConcern Instance
    
{
        
get return _instance; }
    }


    
public void Apply(ComponentModel model, object component)
    
{
        
if (component is IStartable)
        
{
            (component 
as IStartable).Start();
        }

        
else if (model.Configuration != null)
        
{
            String startMethod 
= model.Configuration.Attributes["startMethod"];
 
            
if (startMethod != null)
            
{

                MethodInfo method 
= model.Implementation.GetMethod(startMethod);

                method.Invoke(component, 
null);
            }

        }

    }

}


第二个类是StopConcern,它判断如果组件实现了接口IStartable,则直接调用它的Stop()方法;如果组件是用特性stopMethod,则获取并调用具有stopMethod特性的方法:

public class StopConcern : ILifecycleConcern
{
    
private static readonly StopConcern _instance = new StopConcern();

    
protected StopConcern()
    
{

    }


    
public static StopConcern Instance
    
{
        
get return _instance; }
    }


    
public void Apply(ComponentModel model, object component)
    
{
        
if(component is IStartable)
        
{
            (component 
as IStartable).Stop();
        }

        
else if (model.Configuration != null)
        
{
            String stopMethod 
= model.Configuration.Attributes["stopMethod"];

            
if (stopMethod != null)
            
{
                MethodInfo method 
= model.Implementation.GetMethod(stopMethod);

                method.Invoke(component, 
null);
            }

        }

    }

}


好了,知道了Startable Facility如何管理组件的生命周期,我们就来看看真正的Startable Facility是如何实现的。每一个Facility都是满足这样的一个继承关系:

1 Facility继承关系图

其中的Abstract Facility提供了一些默认的实现,Facility可以直接实现IFacility,也可以继承于Abstract FacilityIFacility的实现如下:

public interface IFacility
{
    
void Init(IKernel kernel, IConfiguration facilityConfig);


    
void Terminate();

}


那么到底如何让组件满足依赖性后就自动执行呢?注意到再Startable FacilityInit()注册了这样的两个事件:

protected override void Init()
{
    converter 
= (ITypeConverter) Kernel.GetSubSystem(SubSystemConstants.ConversionManagerKey);


    Kernel.ComponentModelCreated 
+= 

        
new ComponentModelDelegate(OnComponentModelCreated);

    Kernel.ComponentRegistered 
+= 

        
new ComponentDataDelegate(OnComponentRegistered);

}

 

分别为OnComponentModelCreatedOnComponentRegistered。当我们注册一个组件时首先会出发OnComponentRegistered事件,在它里面判断组件是否满足依赖性,如果不满足,则添加到一个等待列表中,否则就直接启动,然后再对这个等待列表进行检测,看添加改组件后,列表中是否有组件满足了依赖性:

private void OnComponentRegistered(String key, IHandler handler)
{
    
bool startable = (bool) handler.ComponentModel.ExtendedProperties["startable"];

    
if (startable)
    
{
        
if (handler.CurrentState == HandlerState.WaitingDependency)
        
{
            waitList.Add( handler );
        }

        
else
        
{
            Start( key );
        }

    }


    CheckWaitingList();
}


private void CheckWaitingList()
{
    IHandler[] handlers 
= (IHandler[]) waitList.ToArray( typeof(IHandler) );

    IList validList 
= new ArrayList();

    
foreach(IHandler handler in handlers)
    
{
        
if (handler.CurrentState == HandlerState.Valid)
        
{
            validList.Add(handler);

            waitList.Remove(handler);
        }

    }


    
foreach(IHandler handler in validList)
    
{
        Start( handler.ComponentModel.Name );
    }

}


刚才说到,如果满足了依赖性,则会请求创建这个组件:

private void Start(String key)
{
    
object instance = Kernel[key];
}


这时就触发了OnComponentModelCreated事件,这时就该用到开始我们所讲的那两生命周期处理的类了:

private void OnComponentModelCreated(ComponentModel model)
{
    
bool startable = 

        CheckIfComponentImplementsIStartable(model) 
|| HasStartableAttributeSet(model);

    model.ExtendedProperties[
"startable"= startable;

    
if (startable)
    
{
        model.LifecycleSteps.Add( 

            LifecycleStepType.Commission, StartConcern.Instance );

        model.LifecycleSteps.Add( 

            LifecycleStepType.Decommission, StopConcern.Instance );

    }

}


首先还是先判断组件是否实现了IStartable接口或这时候有特性startable,如果没有那也就不用自动启动了,否则就把StartConcernStopConcern分别注册为组件的生命周期开始行为和生命周期结束行为,(关于组件的生命周期的详细内容可以参考我前面写的Castle IOC容器组件生命周期管理)。此时组件进入生命周期开始,会调用StartConcernApply()方法,这时就触发组件的Start()方法,同样在组件销毁时调用StopConcernApply()方法,这时就会调用组件的Stop()方法。这样就完成整个了组件的自动执行与销毁的全过程。

 

上篇:Castle IOC容器实践之Startable Facility

 

参考资料

Castle的官方网站http://www.castleproject.org

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2006-05-14 08:51 TerryLee 阅读(7444) 评论(12) 编辑 收藏

 回复 引用   
#1楼 2006-05-14 09:41 ddee[未注册用户]
老兄,你这样写下去可能比叶子那个系列都详细了^_^
 回复 引用 查看   
#2楼[楼主] 2006-05-14 11:17 Terrylee      
@ddee
呵呵,我尽量写的详细一些,因为Castle的中文文档太少了,而且对于Facility,最好还是了解一下它的一些原理,这样对于实现我们自己的Facility有很大的帮助:-)

 回复 引用 查看   
#3楼 2006-06-07 09:24 阿不      
我在我下载的Castle源码中没有看到Startable 的源码,只有一个目录
 回复 引用 查看   
#4楼[楼主] 2006-06-15 09:08 TerryLee      
@阿不
在目录:Castle\Source Code\InversionOfControl\Castle.MicroKernel\Facilities\Startable下面:-
)

前两天有事回家了,回复的有些晚,见谅!

 回复 引用 查看   
#5楼 2006-06-20 20:05 阿不      
@ TerryLee
我后面找到了,我是没想到会在这个Assembly里面。以前用的Facility都是单独的工程的。

另外,今天想把Startable Facility用到项目中,却发现它并不符合我的要求啊,其实它并不会自动运行(也就是注册Component的时候运行,可能是我前面理解有点问题),而是在被引用的时候自动运行的。
StartableComponent component = kernel["a"] as StartableComponent;
只有当前上面的语句执行了这个组件才被执行。

 回复 引用 查看   
#6楼[楼主] 2006-06-21 08:12 TerryLee      
@阿不
看下面这段代码:
public static void Main() 
    
{
        
//创建Windsor容器
        IWindsorContainer container = new WindsorContainer(new XmlInterpreter("../../BasicUsage.xml")); 
       
        
//添加Facility
        container.AddFacility("startable"new StartableFacility());  
     
        
//添加Program组件 (A)
        container.AddComponent("program"typeof(Program)); 
     
        
//添加Server组件(B)
        container.AddComponent("server"typeof(Server));
    }
是可以自动运行的,在A句处没有满足依赖关系,所以不执行,但是加入B句后,满足了依赖关系,就会自动执行。

 回复 引用 查看   
#7楼 2006-06-21 12:52 阿不      
@TerryLee
喔,这点倒是没有发现,等会儿去看一下。谢谢了。

 回复 引用 查看   
#8楼 2006-06-21 13:10 阿不      
不过,你前一篇的第一个例子我在Test工程中没有找到呀?你是怎么知道它会自己去实例化Server类呢?
 回复 引用 查看   
#9楼 2006-06-21 13:23 阿不      
OK,我明白你前一个例子为什么要注册Server类了,刚才没转过来,它们依赖的关系。但是自动运行是跟Server类没有实际关系的,Startable组件运行时需要这个组件。

而昨天在我的项目中不能自动运行是因为我是先加载注册,后加载StartableFacility的,从而造成了无法自动运行的情况。我是使用BatchRegistrationFacility成批注册组件的,要先注册StartableFacility后注册BatchRegistrationFacility才行的!

 回复 引用 查看   
#10楼[楼主] 2006-06-21 15:07 TerryLee      
@阿不
第一篇的例子是我自己随便写的^_^

 回复 引用   
#11楼 2006-07-21 18:38 lgjsoft[未注册用户]
你好 我这几天为了项目一直拼命看你的IOC
自己也模仿STRATABLE FACILITY 和TYPEDFACTORY FACILITY
写了一下代码
但是我要自己写FACILILITY 有什么好资料介绍一下好吗
能不能介绍一下 如果自己写FACILITY 的话需要怎样的流程
特别是能不能具体介绍一下要设计到的CASTLE 的类和方法.
我看Startable Facility原理分析看的一头雾水


 回复 引用 查看   
#12楼[楼主] 2006-07-23 09:48 TerryLee      
@lgjsoft
其实在这篇文章中,我已经提到了Facility的继承关系,参见上面那副图。

如果你要实现自己的Facility,建议你先以其中的一个已有的Facility为例,看看它的代码:)