技术开发 频道

开源轻量级AOP的实现:项目代码更清晰

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

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

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

  先看项目的组成!

一:先从简单的说吧!4个公开的接口:IStopAdvice

///<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

 

///<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

///<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

///<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

///<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>      
  
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

///<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>      
public void Dispose()  
      {            sink
= null;           
 GC.SuppressFinalize(this);      
}
   }

最后是浮云般的AspectOrientedObject

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

还有AspectOrientedAttribute

///<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>      
  
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;    
   }  
}
0
相关文章