• Castle实践9-在Castle IOC容器中使用AspectSharp(全面剖析AspectSharp Facility)


            在“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~
  • 相关阅读:
    让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法
    检测到有潜在危险的 Request.Form 值
    jQuery校验
    C#客户端的异步操作
    泛型(一)
    c#面试题汇总
    多线程(下)
    多线程(上)
    线程篇(二)
    线程篇(一)
  • 原文地址:https://www.cnblogs.com/wj/p/220552.html
Copyright © 2020-2023  润新知