• 一个轻量级AOP的实现(开源)


        事先声明,本项目参考AOP in C#和园内大神张逸的文章,思路神马的都不是自己的!

        为了让项目的代码看起来更干净,需要一个AOP!

        于是就实现了一个非常简单的,非常轻量级,有多轻量级呢?

        实现的AOP叫做Earthworm(蚯蚓,为什么叫这个?因为它小,它会疏通!,项目的本意也是这样,所以就叫这个!),命名空间Earthworm下有8个代码文件,包括4个公开接口,1个公开特性,1个公开的抽象类,2个内部类。所以对外部调用者而言,可见的只有6个,够轻量级了吧!

       先看项目的组成!

                

          先从简单的说吧!

          4个公开接口:

    IStopAdvice

    View Code
    using System.Runtime.Remoting.Messaging;

    namespace Earthworm
    {
    ///<summary>
    /// 拦截通知接口
    ///</summary>
    public interface IStopAdvice
    {
    ///<summary>
    /// 是否可以继续方法的执行
    ///</summary>
    ///<param name="msg">要执行方法的调用消息</param>
    ///<returns>如果可以继续执行,返回true,否则为false</returns>
    bool CanContinueMethod(IMethodCallMessage msg);
    }
    //////////////////////////////////////////////////////////////////////////
    /**示例
    /// <summary>
    /// 检查对象权限,可以在用户进行关键操作的方法前
    /// 比如btn_DeleteUser_Click方法
    /// </summary>
    class CheckPermission : IStopAdvice
    {
    /// <summary>
    /// 检查当前用户的权限
    /// 如果是管理员则可以继续执行方法
    /// 否则不能执行
    /// </summary>
    /// <param name="msg">要执行方法的调用消息</param>
    /// <returns>是管理员返回true,否则为false</returns>
    public bool CanContinueMethod(IMethodCallMessage msg)
    {
    if (User.CurrentUser.IsAdministrator)
    return true;
    else
    return false;
    }
    }
    *
    */
    //////////////////////////////////////////////////////////////////////////
    }

    IBeforeAdvice

    View Code
    using System.Runtime.Remoting.Messaging;

    namespace Earthworm
    {
    ///<summary>
    /// 前通知接口
    ///</summary>
    public interface IBeforeAdvice
    {
    ///<summary>
    /// 在方法执行前,需要进行的通知
    ///</summary>
    ///<param name="callMsg">要执行方法的调用消息</param>
    void DoAdvice(IMethodCallMessage callMsg);
    }
    //////////////////////////////////////////////////////////////////////////
    /**示例
    /// <summary>
    /// 用户登录时间记录对象
    /// </summary>
    class LoginTimeLogger:IBeforeAdvice
    {
    /// <summary>
    /// 记录当前用户登录到系统的时间
    /// </summary>
    /// <param name="callMsg">要执行方法的调用消息</param>
    public void DoAdvice(IMethodCallMessage callMsg)
    {
    if (callMsg==null)
    {
    return;
    }
    Log.Write(string.Format("用户:{0}于{1}登陆到此系统", User.CurrentUser.Name, DateTime.Now.ToString()));
    }
    }
    *
    */
    //////////////////////////////////////////////////////////////////////////
    }

    IAfterAdvice

    View Code
    using System.Runtime.Remoting.Messaging;

    namespace Earthworm
    {
    ///<summary>
    /// 后通知接口
    ///</summary>
    public interface IAfterAdvice
    {
    ///<summary>
    /// 在方法执行后,需要进行的通知
    ///</summary>
    ///<param name="callMsg">执行完方法的返回消息</param>
    void DoAdvice(IMethodReturnMessage callMsg);
    }
    //////////////////////////////////////////////////////////////////////////
    /**示例
    /// <summary>
    /// 用户登出时间记录
    /// </summary>
    class LogoutTimeLogger:IAfterAdvice
    {
    /// <summary>
    /// 记录当前用户登出系统的时间
    /// </summary>
    /// <param name="callMsg">执行完方法的返回消息</param>
    public void DoAdvice(IMethodReturnMessage callMsg)
    {
    if (callMsg == null)
    {
    return;
    }
    Log.Write(string.Format("用户:{0}于{1}登出此系统", User.CurrentUser.Name, DateTime.Now.ToString()));
    }
    }
    *
    */
    //////////////////////////////////////////////////////////////////////////
    }

    注释比较齐全就不说了,这三个接口是提供给“通知对象”的!

    还有一个是提供给“通知对象”提供者的!

     IAdviceProvider

    View Code
    using System.Collections.Generic;

    namespace Earthworm
    {
    ///<summary>
    /// 通知提供者接口
    /// 实现此接口的对象必须包含无参的构造函数
    /// 否则将无效
    /// 以下所有设置的方法名必须是非static方法的方法名称
    ///</summary>
    public interface IAdviceProvider
    {
    ///<summary>
    /// 前通知集合,其中key为要进行前通知的方法名,value为进行前通知时的处理对象
    ///</summary>
    Dictionary<string, IBeforeAdvice> BeforeAdvices { get; }
    ///<summary>
    /// 拦截通知集合,其中key为要拦截方法名,value为进行拦截时的处理对象
    ///</summary>
    Dictionary<string, IStopAdvice> StopAdvices { get; }
    ///<summary>
    /// 后通知集合,其中key为要进行后通知的方法名,value为进行后通知时的处理对象
    ///</summary>
    Dictionary<string, IAfterAdvice> AfterAdvices { get; }
    }
    //////////////////////////////////////////////////////////////////////////
    /**示例
    /// <summary>
    /// 日志通知提供对象
    /// </summary>
    class LoggerProvider:IAdviceProvider
    {
    private Dictionary<string, IBeforeAdvice> beforeAdvices = new Dictionary<string, IBeforeAdvice>();
    private Dictionary<string, IAfterAdvice> afterAdvices = new Dictionary<string, IAfterAdvice>();
    /// <summary>
    /// 必须包含无参构造函数
    /// </summary>
    public LoggerProvider()
    {
    LoggerAdvice la = new LoggerAdvice();
    //将SetCurrectUser作为前通知方法
    beforeAdvices.Add("SetCurrectUser", la);
    //将Logout作为后通知方法
    afterAdvices.Add("Logout", la);
    }
    /// <summary>
    /// 前通知集合
    /// </summary>
    public Dictionary<string, IBeforeAdvice> BeforeAdvices
    {
    get { return beforeAdvices; }
    }
    /// <summary>
    /// 拦截通知集合,与日志无关,不返回任何信息
    /// </summary>
    public Dictionary<string, IStopAdvice> StopAdvices
    {
    get { return null; }
    }
    /// <summary>
    /// 后通知集合
    /// </summary>
    public Dictionary<string, IAfterAdvice> AfterAdvices
    {
    get { return afterAdvices; }
    }
    }
    */
    //////////////////////////////////////////////////////////////////////////
    }

    当然这个AOP的主要部分不是这个!

    来看最核心的AspectOrientedProperty和Aspect

    AspectOrientedProperty

    View Code
    using System;
    using System.Runtime.Remoting.Contexts;
    using System.Runtime.Remoting.Messaging;

    namespace Earthworm
    {
    ///<summary>
    /// 面向切面属性
    /// 此属性只可以内部使用
    /// 主要职责在于分配侦听接收器
    /// 以及实例化切面处理对象
    ///</summary>
    internal sealed class AspectOrientedProperty : IContextProperty, IDisposable, IContributeServerContextSink
    {
    ///<summary>
    /// 通知提供者对象所在的程序集
    ///</summary>
    private string assemblyName;
    ///<summary>
    /// 通知提供者的对象类型全名
    ///</summary>
    private string className;
    ///<summary>
    /// 构造函数
    ///</summary>
    ///<param name="assemblyName">程序集</param>
    ///<param name="className">对象类型全名</param>
    internal AspectOrientedProperty(string assemblyName, string className)
    {
    this.assemblyName = assemblyName;
    this.className = className;
    }
    ///<summary>
    /// 析构函数哈,省点
    ///</summary>
    ~AspectOrientedProperty()
    {
    Dispose();
    }
    ///<summary>
    /// 不解释
    ///</summary>
    public void Dispose()
    {
    assemblyName = null;
    className = null;
    GC.SuppressFinalize(this);
    }
    ///<summary>
    /// 当上下文冻结时调用
    /// 不需要,不做实现
    ///</summary>
    ///<param name="newContext">要冻结的上下文</param>
    public void Freeze(Context newContext){}
    ///<summary>
    /// 返回一个指示上下文属性是否与新上下文兼容的布尔值。
    ///</summary>
    ///<param name="newCtx">新上下文</param>
    ///<returns>如果该上下文属性可以与给定的上下文中的其他上下文属性共存,则为 true;否则为 false。此处给true</returns>
    public bool IsNewContextOK(Context newCtx)
    {
    return true;
    }
    ///<summary>
    /// 获取将属性添加到上下文中时使用的属性名称
    /// 就叫Earthworm吧
    ///</summary>
    public string Name
    {
    get { return "Earthworm"; }
    }
    ///<summary>
    /// 将第一个接收器放入到目前为止组成的接收器链中,然后将其消息接收器连接到已经形成的链前面
    ///</summary>
    ///<param name="nextSink">到目前为止组成的接收链</param>
    ///<returns>复合接收器链</returns>
    public IMessageSink GetServerContextSink(IMessageSink nextSink)
    {
    return new Aspect(nextSink,assemblyName,className);
    }
    }
    }

    Aspect

    View Code
    using System;
    using System.Runtime.Remoting.Messaging;
    using System.Collections.Generic;
    using System.Xml;
    using System.Reflection;

    namespace Earthworm
    {
    ///<summary>
    /// 方面管理器
    ///</summary>
    internal class Aspect : IMessageSink,IDisposable
    {
    ///<summary>
    /// 消息槽
    ///</summary>
    private IMessageSink sink;
    ///<summary>
    /// 构造函数
    ///</summary>
    ///<param name="sink">消息槽</param>
    ///<param name="assemblyName">处理切面对象的程序集</param>
    ///<param name="className">处理切面对象的全名</param>
    internal Aspect(IMessageSink sink, string assemblyName, string className)
    {
    this.sink = sink;
    IAdviceProvider provider = null;
    try
    {
    provider = Assembly.LoadFrom(assemblyName).CreateInstance(className) as IAdviceProvider;
    beforeAdvices = provider.BeforeAdvices;
    stopAdvices = provider.StopAdvices;
    afterAdvices = provider.AfterAdvices;
    }
    catch{}
    }
    ///<summary>
    /// 异步处理给定的消息,太麻烦,没做
    ///</summary>
    ///<param name="msg">要处理的消息</param>
    ///<param name="replySink">答复消息的答复接收器</param>
    ///<returns>提供一种在调度异步消息之后控制这些消息的方法的对象</returns>
    public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
    {
    return null;
    }
    ///<summary>
    /// 获取接收器链中的下一个消息接收器
    ///</summary>
    public IMessageSink NextSink
    {
    get
    {
    return sink;
    }
    }
    ///<summary>
    /// 同步处理给定的消息
    ///</summary>
    ///<param name="msg">要处理的消息</param>
    ///<returns>响应请求的答复消息</returns>
    public IMessage SyncProcessMessage(IMessage msg)
    {
    IMethodCallMessage call = msg as IMethodCallMessage;
    string methodName = call.MethodName;
    IBeforeAdvice before = FindAdvice(methodName, beforeAdvices);
    if (before != null)
    {
    before.DoAdvice(call);
    }
    IStopAdvice stop = FindAdvice(methodName, stopAdvices);
    IMessage retMsg = null;
    if (stop != null)
    {
    if (stop.CanContinueMethod(call))
    {
    retMsg = NextSink.SyncProcessMessage(msg);
    }
    }
    else
    {
    retMsg = NextSink.SyncProcessMessage(msg);
    }
    if (retMsg!=null)
    {
    IMethodReturnMessage reply = retMsg as IMethodReturnMessage;
    IAfterAdvice after = FindAdvice(methodName, afterAdvices);
    if (after != null)
    {
    after.DoAdvice(reply);
    }
    return retMsg;
    }
    return new ReturnMessage(null, call);

    }
    ///<summary>
    /// 前通知集合
    ///</summary>
    private Dictionary<string, IBeforeAdvice> beforeAdvices ;
    ///<summary>
    /// 拦截通知集合
    ///</summary>
    private Dictionary<string, IStopAdvice> stopAdvices ;
    ///<summary>
    /// 后通知集合
    ///</summary>
    private Dictionary<string, IAfterAdvice> afterAdvices;
    ///<summary>
    /// 在通知集合中找到方法名name的通知
    ///</summary>
    ///<typeparam name="T">泛型</typeparam>
    ///<param name="name">方法名</param>
    ///<param name="advices">通知集合</param>
    ///<returns>泛型对象</returns>
    private T FindAdvice<T>(string name, Dictionary<string, T> advices)
    {
    T ret = default(T);
    if (advices==null)
    {
    return ret;
    }
    lock (advices)
    {
    if (advices.ContainsKey(name))
    {
    return advices[name];
    }
    }
    return ret;
    }
    ///<summary>
    ///
    ///</summary>
    ~Aspect()
    {
    Dispose();
    }
    ///<summary>
    /// 囧囧囧囧囧囧囧囧囧
    ///</summary>
    public void Dispose()
    {
    sink = null;
    GC.SuppressFinalize(this);
    }
    }
    }

    最后是浮云般的AspectOrientedObject

        ///<summary>
    /// 做个假哦
    ///</summary>
    public abstract class AspectOrientedObject:ContextBoundObject{}

    还有AspectOrientedAttribute

    View Code
    using System;
    using System.Runtime.Remoting.Contexts;
    using System.Runtime.Remoting.Activation;

    namespace Earthworm
    {
    ///<summary>
    /// 面向切面属性
    /// 用来配置处理切面的对象
    ///</summary>
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class AspectOrientedAttribute:Attribute,IContextAttribute,IDisposable
    {
    ///<summary>
    /// 处理切面对象的程序集
    ///</summary>
    private string assemblyName;
    ///<summary>
    /// 处理切面对象的全名
    ///</summary>
    private string className;
    ///<summary>
    /// 构造函数
    ///</summary>
    ///<param name="assemblyName">处理切面对象的程序集</param>
    ///<param name="className">处理切面对象的全名</param>
    public AspectOrientedAttribute(string assemblyName, string className)
    {
    this.assemblyName = assemblyName;
    this.className = className;
    }
    ///<summary>
    ///
    ///</summary>
    ~AspectOrientedAttribute()
    {
    Dispose();
    }
    ///<summary>
    /// 囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧
    ///</summary>
    public void Dispose()
    {
    assemblyName = null;
    className = null;
    GC.SuppressFinalize(this);
    }
    ///<summary>
    /// 在给定消息中将上下文属性返回给调用方
    ///</summary>
    ///<param name="msg">将上下文属性添加到的 消息</param>
    public void GetPropertiesForNewContext(IConstructionCallMessage msg)
    {
    msg.ContextProperties.Add(new AspectOrientedProperty(assemblyName,className));
    }
    ///<summary>
    /// 返回一个布尔值,指示指定上下文是否满足上下文属性的要求
    ///</summary>
    ///<param name="ctx">当前上下文属性检查所依据的上下文</param>
    ///<param name="msg">构造调用,需要依据当前上下文检查其参数</param>
    ///<returns>如果传入的上下文一切正常,则为 true;否则为 false。给false</returns>
    public bool IsContextOK(Context ctx, IConstructionCallMessage msg)
    {
    return false;
    }
    }
    }

        附上整个项目:下载

       需探讨,加908165245!

  • 相关阅读:
    Educational Codeforces Round 30 B【前缀和+思维/经典原题】
    Educational Codeforces Round 30 A[水题/数组排序]
    洛谷 P2415 集合求和【数学公式/模拟】
    洛谷 P2689 东南西北【模拟/搜索】
    洛谷 P1012 拼数 [字符串]
    codeforces 869C The Intriguing Obsession【组合数学+dp+第二类斯特林公式】
    洛谷 P3927 SAC E#1
    洛谷P3929 SAC E#1
    洛谷P3926 SAC E#1
    codeforces 868B The Eternal Immortality【暴力+trick】
  • 原文地址:https://www.cnblogs.com/wushilonng/p/2247186.html
Copyright © 2020-2023  润新知