動態織入的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:在接口的方法上進行標記,如上文代碼;
