一个轻量级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!

posted @ 2011-11-13 12:46  方外老和尚  阅读(3579)  评论(7编辑  收藏