叶子的家

~●    ~●  ~●          ~●   ~●~●                           ○
    离成功还很远,距离长着叻,Fighting!
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

        在“Castle实践8”介绍了A#的使用方法,那么A#如何和Castle IOC容器结合起来使用呢?在Castle的官方falicicies库中,提供了AspectSharp Facility来让我们可以很简单在IOC中使用A#。我把使用方法放在最后,题目说了是要全面剖析这个facility的原理,借助这次分析让我们对Castle IOC中的Falicity编写有更深的了解。

        编写一个facility之前,最重要的就是要明确这个falicity的目的。通过“实践8”知道,要使用一个aop过的对象,需要调用engine.WrapClass或者engine.WrapInterface来对目的对象包装,那么得出这个facility的目的就是:当用户向IOC容器请求组件的时候,根据aop的配置自动包装组件再交给客户使用。

        明白了需求,那么就开始分析吧:

protected override void Init()
{
    
if (FacilityConfig == nullreturn;

    
// 第一步
    RegisterAspectEngine();
    
// 第二步
    RegisterInterceptor();

    
// 第三步
    Kernel.ProxyFactory = new AopProxyFactory();

    
// 第四步
    _engine = (AspectEngine) Kernel[ typeof(AspectEngine) ];

    
// 第五步:向IOC里面加入任何组件的时候,OnComponentRegistered会回调
    Kernel.ComponentRegistered += new ComponentDataDelegate(OnComponentRegistered);
}


第一步:
private void RegisterAspectEngine()
{
    
// 获取当前facility的配置,相当于获取了a#的配置
    String contents = FacilityConfig.Value;

    
// 创建a#的builder
    AspectEngineBuilder builder = new AspectLanguageEngineBuilder(contents);

    ComponentModel model 
= 
        
new ComponentModel("aspectsharp.engine"
            
typeof(AspectEngine), typeof(AspectEngine));
    
    
// a#的builder作为扩张属性
    model.ExtendedProperties.Add("builder", builder);
    
// engine激活的时候执行AspectEngineActivator
    model.CustomComponentActivator = typeof(AspectEngineActivator);

    
// 把a# engine作为组件加入ioc中
    Kernel.AddCustomComponent( model );
}


第二步:
private void RegisterInterceptor()
{
    
// 讲AopInterceptor加入IOC中
    Kernel.AddComponent( "aspectsharp.interceptor"typeof(AopInterceptor) );
}


第三步:注册ioc的proxy工厂
/// <summary>
/// Specialization of <see cref="Castle.Windsor.Proxy.DefaultProxyFactory"/>
/// that checks for aspects in the model and potential mixins.
/// </summary>
public class AopProxyFactory : DefaultProxyFactory
{
protected override void CustomizeContext(GeneratorContext context, IKernel kernel, 
    ComponentModel model, 
object[] arguments)
{
    
// 获取a#的配置
    AspectDefinition aspect = (AspectDefinition) model.ExtendedProperties["aop.aspect"];

    
if (aspect == nullreturn;

    
// 得到所有mixin
    MixinDefinitionCollection mixins = aspect.Mixins;

    
foreach(MixinDefinition definition in mixins)
    {
        Type mixinType 
= definition.TypeReference.ResolvedType;
        
        
try
        {
            
// 创建一个minix对象并交给dynamicproxy,dynamicproxy产生proxy的时候会用到
            context.AddMixinInstance( Activator.CreateInstance( mixinType ) );
        }
        
catch(Exception e)
        {
            
throw new ApplicationException("Could not instantiate mixin " + mixinType.FullName, e);
        }
    }
}

protected override void CustomizeProxy(object proxy, GeneratorContext context, IKernel kernel, ComponentModel model)
{
    
// 获取在上面的CustomizeContext函数中创建的mixin对象
    object[] mixins = context.MixinsAsArray();

    
// 所有实现了IProxyAware的mixin对象,都会把实际的代理set到里面交给客户处理
    
//在“Castle实践8”中的SecurityMixin就是实现了IProxyAware的,在SecurityMixin类
    
//上下文中可以任意使用proxy,这下明白了吧。
    for(int i=0; i < mixins.Length; i++)
    {
        
object mixin = mixins[i];
        
        
if (mixin is IProxyAware)
        {
            (mixin 
as IProxyAware).SetProxy(proxy);
        }
    }
}


第四步:激活a# engine,导致AspectEngineActivator执行
protected override object InternalCreate()
{
    
// 获取a#的builder
    AspectEngineBuilder builder = (AspectEngineBuilder) 
        
base.Model.ExtendedProperties["builder"];

    System.Diagnostics.Debug.Assert( builder 
!= null );

    
// 创建engine
    return builder.Build();
}


第五步:向IOC里面加入任何组件的时候,OnComponentRegistered会回调
private void OnComponentRegistered(String key, IHandler handler)
{
    
// 检查a#配置中是否包含组件的“切面”
    
//就是当前加入的这个组件是否需要aop(怎么说呢??表达不太清晰,大家应该明白吧。请原谅~~)
    AspectDefinition[] aspects = 
        _engine.AspectMatcher.Match( handler.ComponentModel.Implementation, 
        _engine.Configuration.Aspects );

    
if (aspects.Length != 0)
    {
        
// 如果组件需要aop,则合并配置中对此组件的切面定义
        
//并将定义加入到组件的扩张属性中
        handler.ComponentModel.ExtendedProperties["aop.aspect"= Union(aspects);

        
// 向组件加入拦截器
        
//当向ioc请求组件对象的时候,拦截器的作用就是根据上面的定义来产生一个组件的proxy
        handler.ComponentModel.Interceptors.Add( 
            
new InterceptorReference( typeof(AopInterceptor) ) );
    }
}

private AspectDefinition Union(AspectDefinition[] aspects)
{
    
// 这里作用是合并对组件的“切面”配置内容
    
//但作者todo了,未完成?

    
if (aspects.Length == 1)
    {
        
return aspects[0];
    }

    
// TODO: Merge aspects

    
return aspects[0];
}


         这时候回头来看看,我们的目的是自动包装,上面的代码中没有调用A# engine的WrapClass和WrapInterface的,其实两个wrap做的是调用DefaultProxyFactory来产生代理的,这里给AopProxyFactory代替了。而真正请求一个组件的时候,产生代理的工作都是在AopInterceptor中处理的。


/// <summary>
/// Summary description for AopInterceptor.
/// </summary>
[Transient]
public class AopInterceptor : IMethodInterceptor, IOnBehalfAware
{
    
private IKernel _kernel;
    
private AspectEngine _engine;
    
private IInvocationDispatcher _dispatcher;

    
public AopInterceptor(AspectEngine engine, IKernel kernel)
    {
        _engine 
= engine;
        _kernel 
= kernel;
    }

    
public void SetInterceptedComponentModel(ComponentModel target)
    {
        
// 获取组件的aop配置
        AspectDefinition aspectDef = (AspectDefinition) 
            target.ExtendedProperties[
"aop.aspect"];

        System.Diagnostics.Debug.Assert( aspectDef 
!= null );

        
// InvocationDispatcher用于proxy的方法分派,ContainerInvocationDispatcher重写了
        
//ObtainInterceptorInstance方法,唯一的作用是:尝试从IOC中获取拦截器对象
        _dispatcher = new ContainerInvocationDispatcher(aspectDef, _kernel);
        _dispatcher.Init(_engine);
    }

    
public object Intercept(IMethodInvocation invocation, params object[] args)
    {
        
// a#内幕:_dispatcher.Intercept会处理客户的函数调用
        
//Intercept方法会从ObtainInterceptorInstance获取拦截器实例
        
//(ContainerInvocationDispatcher中重写的方法起作用了)
        
// 如果没有拦截器则直接Proceed,有拦截器则在拦截器进行处理
        
//这是a#拦截的一个简单过程,详细你可以参考:a#中的DefaultInvocationDispatcher源码
        return _dispatcher.Intercept( (IInvocation) invocation, args);
    }
}


而在ContainerInvocationDispatcher重写的ObtainInterceptorInstance是这样的:
/// <summary>
/// 获取拦截器对象
/// </summary>
protected override IMethodInterceptor ObtainInterceptorInstance(Type adviceType)
{
    
if (_kernel.HasComponent( adviceType ))
    {
        
// 方式一:从IOC中获取
        
//如果我们把拦截器注册进IOC里面,这里就直接获取
        try
        {
            
return (IMethodInterceptor) _kernel[adviceType];
        }
        
catch(InvalidCastException ex)
        {
            
// In this case, the specified interceptor
            
// does not implement the IMethodInterceptor from
            
// AopAlliance

            String message 
= String.Format("The interceptor {0} does " + 
                
"not implement AopAlliance.Interceptor.IMethodInterceptor", adviceType.FullName); 

            
throw new ApplicationException(message, ex);
        }
    }

    
// 方式二:从A#的DefaultInvocationDispatcher中获取
    
//A#中对拦截器对象实例是有缓存处理的(一个HashTable:_type2AdviceInstance)
    return base.ObtainInterceptorInstance(adviceType);
}


        分析结束啦~ ,最后放上使用方法,很简单的:

1)配置:
<configuration>
    
<facilities>
        
<facility id="aspectsharp">
<![CDATA[
import AopDemo.Interceptors
import AopDemo.Mixins

aspect log for [AopDemo]
    pointcut method(*)
        advice(LoggerInterceptor)
    end
end

aspect Security for [AopDemo]
    include SecurityMixin
    pointcut method(*)
        advice(SecurityCheckInterceptor)
    end
end
]]>
        
</facility>
    
</facilities>
</configuration>


2)初始化容器:
container = new WindsorContainer(@"../../aspectsharp.ioc.xml");
container.AddFacility(
"aspectsharp"new AspectSharpFacility()) ;
container.AddComponent(
"persondao"typeof(PersonDao));


3)使用组件:
PersonDao dao = container["persondao"as PersonDao;
dao.Create(
"AAA");
...

完整demo下载地址:
http://www.wjshome.com/Income/Others/Castle.AspectSharp%20Facility.Demo.rar

bye~