在“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~

转载于:https://www.cnblogs.com/laiwen/archive/2005/09/07/231651.html

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

  1. 头条一面:Spring IOC容器中只存放单例Bean吗?

    最近,很多小伙伴出去面试,感觉自己面的不是很理想,回来后,不少小伙伴把面试题做了记录发给我,让我给大家解析下,然后发出来.当我看到这些面试题时,快速在脑海中构建起了整个知识体系,从基础到框架.从分布式 ...

  2. Spring5 - 向IOC容器中添加组件的4种方式

    文章目录 概述 方式一: @CompentScan 适用场景 Code 方式二: @Bean 适用场景 Code 方式三: @Import 适用场景 Code Demo1 Code Demo2 + 实 ...

  3. java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

    前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息. 其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Sprin ...

  4. 六、spring之通过FactoryBean为ioc容器中添加组件

    前面我们已经介绍了几种为容器中添加组件的方法,今天一起学习通过FactoryBean添加组件的方法. 首先我们准备一个类,也就是我们需要注册进spring的ioc容器中的类 类Color: // 不必 ...

  5. IOC 容器中那些鲜为人知的细节(关于 FactoryBean 和 BeanFactory)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) 在 Spring 中,有两个很容易混淆的类:BeanFactory 和 FactoryBean. BeanFa ...

  6. Spring中将BeanDefinition注册到IOC容器中

    Spring中将BeanDefinition注册到IOC容器中 XML配置元信息 <bean name="-" - /> 注解: @Bean,@Component,@I ...

  7. IOC容器中bean的生命周期,iocbean生命周期

    原文地址:http://www.bkjia.com/Javabc/1149957.html IOC容器中bean的生命周期,iocbean生命周期 一.Bean的生命周期 Spring IOC容器可以 ...

  8. IOC容器中bean的生命周期

    一.Bean的生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: (1).通 ...

  9. IOC 容器中那些鲜为人知的细节

    通过前面章节中对Spring IOC 容器的源码分析,我们已经基本上了解了Spring IOC 容器对Bean 定义资源的定位.载入和注册过程,同时也清楚了当用户通过getBean()方法向IOC 容 ...

最新文章

  1. AI让交通管理省时、省心、省力
  2. Boost:在向量中打印值
  3. 运维祈求不宕机_[国庆特辑] 程序员应该求谁保佑才能保证不宕机?
  4. Sentinel降级简介_分布式系统集群限流_线程数隔离_削峰填谷_流量控制_速率控制_服务熔断_服务降级---微服务升级_SpringCloud Alibaba工作笔记0038
  5. condition_variable的怪事
  6. mysql存储过程删除_MySQL 存储过程删除大表
  7. SQL Server数据库表锁定原理以及如何解除表的锁定
  8. Spring ——《第二章》Spring中的Bean
  9. Lua5.2 请求 luasocket 相关模块时的 multiple-lua-vms-detected
  10. 数据库开发综合案例——仓库管理系统设计
  11. x2分布临界值表(卡方分布)
  12. 深度Linux关闭搜狗后没法输入,在Deepin系统中搜狗输入法问题反馈和一些问题的解决方法...
  13. ISA防火墙简单安装配置实例
  14. 夏威夷大学计算机专业排名,夏威夷大学(美国夏威夷大学排名)
  15. 2022 年牛客多校第四场补题记录
  16. 【易语言界面开发系列教程之(EX_UI使用系列教程 ——1-8节)】
  17. 使用该设备需要WIA驱动程序
  18. 海康威视:单季盈利下滑与华为并无关系,2019 年将进入 AI 落地阶段...
  19. 偏振1_经过两个偏振片最大光强问题
  20. matlab坐标用星星表示什么,用Matlab实现简易图片中的星星计数及位置标记--陈宗华...

热门文章

  1. 用C#开发.NET CF 蓝牙通信模块
  2. 10 | 案例篇:系统的软中断CPU使用率升高,我该怎么办?
  3. S8 Linux磁盘与文件系统管理命令
  4. 短代码 html,WordPress的短代码问题嵌入HTML格式
  5. java构造顺序_Java构造顺序
  6. 脚本升级_手把手教你升级到Database 19c(3)| 终章教程
  7. zcmu 4935(排序)
  8. ubutun安装MySQL hive配置_Hive安装以及部署(Ubuntu-MySql)
  9. Spring Boot参数校验以及分组校验的使用
  10. 零起点入门教程:1分钟极简操作,新手也能搭应用