实现简易的AOP框架(二)

在上一篇文章中我介绍了AOP的实现原理,下面我们就使用Emit来实现一个简单的AOP框架,最后再写一个使用这个框架的例子来检测一下效果。

1、SimpleAOP项目文件结构

由项目文件截图可以看出这个SimpleAOP确实挺Simple呀,项目虽然简单,不过用来学习AOP思想还是足够用的。
项目的主要功能部分是用Emit和Attribute实现的,如果大家对Emit和Attribute不了解的话,建议大家先学习一下IL&反射系列文章EMIT学习系列文章
这里写图片描述
下面逐一介绍项目中各文件的作用。

2、AspectContext

上一篇文章中两个切面类的WriteLog方法都没有参数,所以我们无法在WriteLog中获取原Add方法的相关信息,也就无法做一些跟原Add方法有关的操作,有的人可能说反正现在也用不到考虑那么多干嘛!你可能现在用不到,万一你以后需要校验参数格式呢?万一你以后需要记录方法返回值呢?万一你以后需要记录日志来自哪个方法呢?万一你以后需要记录异常的信息呢?等等……
这个AspectContext就是用来记录这些内容的,本例中的AspectContext记录了方法、参数、返回值、异常的相关内容。如果在上文的BeforeActionAttribute、AfterActionAttribute加上AspectContext的话,那它的作用应该是这样的:

public class BeforeActionAttribute:Attribute
{
    public void WriteLog(AspectContext aspectContext)
    {
        //【获取原方法相关信息】
        string methodName = aspectContext.Method.MethodName;
        object[] paramValues = aspectContext.ParameterList.Select(delegate(ParameterMetaData parameter)
        {
            return parameter.ParameterValue;
        }).ToArray();
        object returnValue = aspectContext.ReturnValue.Value;
        Exception ex = aspectContext.Exception.Ex;

        //模拟记录日志
        Console.WriteLine("BeforeAction");
    }
}
public class AfterActionAttribute:Attribute
{
    public void WriteLog(AspectContext aspectContext)
    {
        //【获取原方法相关信息】
        string methodName = aspectContext.Method.MethodName;
        object[] paramValues = aspectContext.ParameterList.Select(delegate(ParameterMetaData parameter)
        {
            return parameter.ParameterValue;
        }).ToArray();
        object returnValue = aspectContext.ReturnValue.Value;
        Exception ex = aspectContext.Exception.Ex;

        //模拟记录日志
        Console.WriteLine("AfterAction");
    }
}

有了这个AspectContext我们就可以在切面类中获取到原方法的一些内容,如果需要的话我们可以在切面类中做一些与原方法相关操作,这样切面类的作用就更加丰富了。

3、*MetaData

由于AspectContext中存储了方法、参数、返回值、异常的相关内容,为了体现OOP的开发思想,我新建了四个类来分别封装方法、参数、返回值、异常的相关内容,在AspectContext只需要保存跟这四个类相关的对象就可以了。

Metadata中定义了四个类:

  • ExceptionMetadata:用于保存程序中exception的信息
  • MethodMetadata :用于保存程序中方法的信息(目前只有方法名)
  • ParameterMetadata:用于保存程序中方法的参数信息
  • ReturnValueMetadata:用于保存程序中方法的返回值信息

4、AspectAttribute

下一步要定义切面了,在AOP框架中定义的切面其实起到了占位符的作用。客户端之所以能在方法中注入一些自定义代码,是因为我们在AOP框架中预留了允许代码注入的位置,再讲得通俗一些,客户端之所以能在方法中注入一些自定义代码,是因为框架就是这么设计的,这是设计好的,要的就是这效果。
既然这是设计好的,那代码的注入方式也就必须按照设计好的方式来,那就是用户自定义的切面类必须继承自BeforeActionAttribute、AfterActionAttribute或HandleExceptionAttribute,只有这样才能把用户自定义的切面类放到父类对应的占位符位置。
下面四个类中AspectAttribute类不是必须存在的,由于BeforeActionAttribute、AfterActionAttribute、HandleExceptionAttribute都要继承自Attribute,而且都有一个参数类型为AspectContext的Action方法,所以为这三个类创建了一个AspectAttribute基类。

public abstract class AspectAttribute:Attribute
{
    public abstract void Action(AspectContext aspectContext);
}   
public class BeforeActionAttribute:AspectAttribute
{

    public override void Action(AspectContext aspectContext)
    {
        Console.WriteLine("BeforeAction");
    }
}   
public class AfterActionAttribute:AspectAttribute
{
    public override void Action(AspectContext aspectContext)
    {
        Console.WriteLine("AfterAction");
    }
}   
public class HandleExceptionAttribute:AspectAttribute
{
    public override void Action(AspectContext aspectContext)
    {
        Console.WriteLine("HandleException");
    }
}

5、ProxyFactory

ProxyFactory是SimpleAOP对外的接口,对于需要使用AOP的类,必须使用ProxyFactory来生成相应的代理类。如果用上一篇文章中的示例来解释那就是:ProxyFactory能够根据ICal和Calculator动态生成DynamicCalculator,最后返回DynamicCalculator类的实例。

ProxyFactory类中只有一个静态方法,它就是用来生成动态代理类的。

public class ProxyFactory
{
    public static T CreateProxy<T>(Type realProxyType)
    {
        DynamicProxyGenerator dynamicProxyGenerator = new DynamicProxyGenerator(typeof(T), realProxyType);
        Type type = dynamicProxyGenerator.GenerateType();
        T result = (T)System.Activator.CreateInstance(type);
        return result;
    }
}

6、DynamicProxyGenerator

这个类是整个框架的核心,ProxyFactory就是通过调用DynamicProxyGenerator中的GenerateType()方法实现根据现有type生成新type功能的。
我们在DynamicProxyGenerator中完成对现有type方法的拦截操作,并在拦截后根据方法本身Attribute依附情况进行代码注入。

public DynamicProxyGenerator()
{
}

public DynamicProxyGenerator(Type interfacType, Type realProxyType)
{
    this._interfaceType = interfacType;
    this._realProxyType = realProxyType;
}

public Type GenerateType()
{
    //构造程序集
    BuildAssembly();
    //构造模块
    BuildModule();
    //构造类型
    BuildType();
    //构造字段
    BuildField();
    //构造函数
    BuildConstructor();
    //构造方法
    BuildMethods();
    Type dynamicType = typeBuilder.CreateType();
    assemblyBuilder.Save(AssemblyFileName);
    return dynamicType;
}

项目下载地址:http://download.csdn.net/detail/xiaouncle/9872965

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

changuncle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值