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  ==   null return ;

    
//  第一步
    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  ==   null return ;

    
//  得到所有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~

你可能感兴趣的:(Aspect)