話續前文 : 自己實現簡單的AOP(一)簡介
在前一篇文章中,對AOP的實現方式做了一個簡單介紹。接下來,引入Attribute 為方法指定增強對象,由此實現一個簡單的AOP。
注意:指定的是增強對象,“對象”,也就是說Attribute標記,標記的其實是一個對象。由此、使用多態便可輕松實現增強的擴展。
自定義的Attribute
/// <summary> /// 為方法標記指定的增強對象 /// <para>指定的增強,可通過代理 DelayPRoxy 織入</para> /// </summary> [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] public sealed class AdviceAttribute : Attribute { /// <summary> /// 增強對象 /// </summary> public AdviceAbstract Advice { get; private set; } /// <summary> /// 使用指定類型的默認增強對象 /// <para>如果類型為空 則不使用任何增強</para> /// </summary> /// <param name="type"></param> public AdviceAttribute(Type type) : this(type, string.Empty) { } /// <summary> /// 使用公有靜態方法名初始化指定類型的增強對象 /// <para>如果類型為空 則不使用任何增強</para> /// </summary> /// <param name="type">類型</param> /// <param name="methodName"> /// 公有靜態方法名 /// <para>如果方法名為空,調用默認構造函數</para> /// </param> public AdviceAttribute(Type type, string methodName) { // 如果類型為空 則不使用任何增強 if (type == null) { this.Advice = null; return; } if (string.IsNullOrWhiteSpace(methodName)) { this.Advice = Activator.CreateInstance(type) as AdviceAbstract; return; } this.Advice = type.InvokeMember( methodName, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static, null, null, null) as AdviceAbstract; } #region 以下兩種方式效果不是很好,不推薦使用,故 構造函數私有化 /// <summary> /// 使用參數列表初始化指定類型的增強對象 /// </summary> /// <param name="type">類型</param> /// <param name="objs">參數列表</param> private AdviceAttribute(Type type, params object[] objs) { this.Advice = Activator.CreateInstance(type, objs) as AdviceAbstract; } /// <summary> /// 使用命名參數初始化指定類型的增強對象 /// </summary> /// <param name="namedParameter"> /// 以 冒號 和 分號 分割的形參的命名參數列表 /// <para>支持的數據類型有:string, int, bool 及 可通過靜態方法Parse 反序列化的類型</para> /// </param> /// <param name="type"></param> private AdviceAttribute(string namedParameter, Type type) { this.Advice = ReflectionUtil.InvokeConstructor(type, namedParameter) as AdviceAbstract; } #endregion }
增強的抽象類 和 自定義的增強
/// <summary> /// 抽象的增強類 /// </summary> public abstract class AdviceAbstract { public abstract IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage); } public class MyAdvice : AdviceAbstract { public override IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage) { this.BeforeInvoke(target); IMessage message = DelayProxyUtil.InvokeBeProxy(target, callMessage); this.AfterInvoke(target); return message; } protected virtual void BeforeInvoke(MarshalByRefObject target) { Console.WriteLine("Before"); } protected virtual void AfterInvoke(MarshalByRefObject target) { Console.WriteLine("After"); } }
有了如上的兩個組件,再借助代理類 DelayProxy<T>,將增強織入,簡單的AOP就已經初具原形了。
/// <summary> /// 支持泛型、支持延遲初始化的代理類, 可為 MarshalByRefObject 的子類型提供代理 /// <para>在執行代理的過程中,獲取 AdviceAttribute 所指定的增強,并織入該增強</para> /// </summary> public class DelayProxy<T> : RealProxy where T : MarshalByRefObject { private static object objLock = new object(); /// <summary> /// 被代理的對象 /// </summary> private T target; /// <summary> /// 是否延遲初始化 /// <para>True:延遲, False: 不延遲</para> /// </summary> private readonly bool delay; public DelayProxy(T target, bool delay) : base(typeof(T)) { this.target = target; this.delay = delay; } /// <summary> /// 調用被代理對象 /// <para>支持 out ref 參數</para> /// </summary> /// <param name="msg"></param> /// <returns></returns> public override IMessage Invoke(IMessage msg) { if (this.delay && this.target == null) { lock (objLock) { if (this.delay && this.target == null) { T instance = Activator.CreateInstance(typeof(T)) as T; // 自動裝配屬性 // 為屬性對象啟用代理,并延遲初始化被代理的對象 // DelayProxyUtil.AutowiredProperties(instance); this.target = instance; } } } IMethodCallMessage callMessage = (IMethodCallMessage)msg; AdviceAttribute attri = ReflectionUtil.GetCustomAttribute<AdviceAttribute>(callMessage.MethodBase); if (attri != null && attri.Advice != null) { return attri.Advice.Invoke(this.target, callMessage); } return DelayProxyUtil.InvokeBeProxy(this.target, callMessage); } }
附源碼(MVC4的項目 沒有packages文件夾):http://files.VEVb.com/files/08shiyan/AOPDemo.zip
該源碼中還實現了被代理對象的延遲初始化。
未完待續...
新聞熱點
疑難解答