動態織入的AOP實現,有兩種方法:
第一類,借助於Remoting命名空間下的幾個類,通過獲取當前上下文及反射的機制來實現,這需要被AOP的類需要繼承自arshalByRefObject
或者ContextBoundObject;
第二類,原理是基於動態代理的思想,即在運行時動態構造一個原有類的子類,這樣就可以在子類的重載方法中插入額外代碼。
這兩類方法,都有顯著的不足,前者直接要求我們繼承固定類,后者呢,除非父類方法被定義為virtual,或者方法定義於某個接口,否則就不能被重載,這就是得“攔截”並不是可以對任意的方法進行的。
動態織入局限於CLR的限制,不能實現對任何方法進行AOP,如果要突破這個限制,只能采用靜態織入的方法,靜態織入采用。靜態織入突破OO設計模式,可以攔截所有的方法甚至構造函數或屬性訪問器,因為它是直接修改IL。還有,因為它在運行前修改原有程序集,也就基本不存在運行時的性能損失問題了。它的不足,一方面是框架較復雜,實現較麻煩,依賴於對底層的IL指令集的操縱;
一:繼承自ContextBoundObject的實現
幫助類:
public class SecurityAspect : IMessageSink { internal SecurityAspect(IMessageSink next) { _next = next; } private IMessageSink _next; public IMessageSink NextSink { get { return _next; } } public IMessage SyncProcessMessage(IMessage msg) { Preprocess(msg); IMessage returnMethod = _next.SyncProcessMessage(msg); return returnMethod; } public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) { throw new InvalidOperationException(); } private void Preprocess(IMessage msg) { if (!(msg is IMethodMessage)) return; IMethodMessage call = msg as IMethodMessage; Type type = Type.GetType(call.TypeName); string callStr = type.Name + "." + call.MethodName; Console.WriteLine("Security validating : {0} for {1}", callStr, Environment.UserName); // call some security validating code } } public class SecurityProperty : IContextProperty, IContributeObjectSink { public IMessageSink GetObjectSink(MarshalByRefObject o, IMessageSink next) { return new SecurityAspect(next); } public string Name { get { return "SecurityProperty"; } } public void Freeze(Context newContext) { } public bool IsNewContextOK(Context newCtx) { return true; } } [AttributeUsage(AttributeTargets.All)] public class SecurityAttribute : ContextAttribute { public SecurityAttribute() : base("Security") { } public override void GetPropertiesForNewContext(IConstructionCallMessage ccm) { ccm.ContextProperties.Add(new SecurityProperty()); } }
調用方:
class Program { static void Main(string[] args) { SampleClass s = new SampleClass(); s.DoSomething(); } } [Security] [Tracing] public class SampleClass: ContextBoundObject { public void DoSomething() { Console.WriteLine("do something"); } }
二:Virtual方法及接口的實現
幫助類:
public class LogHandler : ICallHandler { /// <summary> /// 執行順序 /// </summary> public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { Console.WriteLine("方法名: {0}", input.MethodBase.Name); Console.WriteLine("參數:"); for (var i = 0; i < input.Arguments.Count; i++) { Console.WriteLine("{0}: {1}", input.Arguments.ParameterName(i), input.Arguments[i]); } Console.WriteLine("方法執行前的處理"); var retvalue = getNext()(input, getNext); Console.WriteLine("方法執行后的處理"); return retvalue; } } public class LogHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler(IUnityContainer container) { return new LogHandler(); } }
調用方:
public interface ISample { [LogHandler] void DoSomething(); void DoSomethingNoAop(); } class Sample1 : ISample { public void DoSomething() { Console.WriteLine("Sample1 do something"); } public void DoSomethingNoAop() { Console.WriteLine("Sample1 do something no aop"); } } public class SampleClass { [LogHandler] public virtual void SampleVirtual() { Console.WriteLine("Virtual method"); } public void Sample() { Console.WriteLine("Sampe method"); } } class Program { static void Main() { //針對接口 var container1 = new UnityContainer() .AddNewExtension<Interception>() .RegisterType<ISample, Sample1>(); container1 .Configure<Interception>() .SetInterceptorFor<ISample>(new InterfaceInterceptor()); container1 .Configure<Interception>() .SetInterceptorFor<SampleClass>(new VirtualMethodInterceptor()); var sample1 = container1.Resolve<ISample>(); sample1.DoSomething(); sample1.DoSomethingNoAop(); //針對虛擬方法 var sample2 = container1.Resolve<SampleClass>(); sample2.SampleVirtual(); sample2.Sample(); Console.ReadKey(); } }
可以看到,第二種方法是用Unity實現的,關於Unity,這里多說兩句:
Unity的AOP可以從3種標記的情況攔截:
TransparentProxyInterceptor:直接在類的方法上進行標記,但是這個類必須繼承MarshalByRefObject;
VirtualMethod:直接在類的虛方法上進行標記,如上文代碼;
InterfaceInterceptor:在接口的方法上進行標記,如上文代碼;