本節目錄:
AOP介紹
面向切面編程(Aspect Oriented Programming,英文縮寫為AOP),通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。
AOP是OOP的延續,是軟件開發中的一個熱點.
常用於:
Authentication
Caching
Lazy loading
Transactions
AOP基本原理
普通類
class Person : MarshalByRefObject
{
public string Say()
{
const string str = "Person's say is called";
Console.WriteLine(str);
return str;
}
}
代理類
public class Proxy<T> : RealProxy where T : new()
{
private object _obj;
public Proxy(object obj)
: base(typeof(T))
{
_obj = obj;
}
public override IMessage Invoke(IMessage msg)
{
Console.WriteLine("{0}:Invoke前", DateTime.Now);
var ret = ((IMethodCallMessage)msg).MethodBase.Invoke(_obj, null);
Console.WriteLine("{0}:Invoke后", DateTime.Now);
return new ReturnMessage(ret, null, 0, null, null);
}
}
執行
static void Main(string[] args)
{
var per = new Proxy<Person>(new Person()).GetTransparentProxy() as Person;
if (per != null)
{
var str = per.Say();
Console.WriteLine("返回值:" + str);
}
Console.ReadKey();
}
AOP框架
AOP有動態代理和靜態IL織入.
本節主要介紹動態代理方式,靜態可參考PostSharp.
Castle Core
原理:本質是創建繼承原來類的代理類.重寫虛方法實現AOP功能.
只需引用:
Install-Package Castle.Core
(在Castle的2.5以上版本,已經將 Castle.DynamicProxy2.dll 里有內容,集成到 Castle.Core.dll 中。)
Simple Class
public abstract class Person
{
public virtual void SayHello()
{
Console.WriteLine("我是{0}方法", "SayHello");
}
public virtual void SayName(string name)
{
Console.WriteLine("我是{0}方法,參數值:{1}", "SayName", name);
}
public abstract void AbstactSayOther();
public void SayOther()
{
Console.WriteLine("我是{0}方法", "SayOther");
}
}
interceptor
public class SimpleInterceptor : StandardInterceptor
{
protected override void PreProceed(IInvocation invocation)
{
Console.WriteLine("攔截器調用方法前,方法名是:{0}。", invocation.Method.Name);
}
protected override void PerformProceed(IInvocation invocation)
{
Console.WriteLine("攔截器開始調用方法,方法名是:{0}。", invocation.Method.Name);
var attrs = invocation.MethodInvocationTarget.Attributes.HasFlag(MethodAttributes.Abstract);//過濾abstract方法
if (!attrs)
{
base.PerformProceed(invocation);//此處會調用真正的方法 invocation.Proceed();
}
}
protected override void PostProceed(IInvocation invocation)
{
Console.WriteLine("攔截器調用方法后,方法名是:{0}。", invocation.Method.Name);
}
}
Main
static void Main(string[] args)
{
var generator = new ProxyGenerator(); //實例化【代理類生成器】
var interceptor = new SimpleInterceptor(); //實例化【攔截器】
//使用【代理類生成器】創建Person對象,而不是使用new關鍵字來實例化
var person = generator.CreateClassProxy<Person>(interceptor);
Console.WriteLine("當前類型:{0},父類型:{1}", person.GetType(), person.GetType().BaseType);
Console.WriteLine();
person.SayHello();//攔截
Console.WriteLine();
person.SayName("Never、C");//攔截
Console.WriteLine();
person.SayOther();//普通方法,無法攔截
person.AbstactSayOther();//抽象方法,可以攔截
Console.ReadLine();
}
Castle Windsor
特性式AOP
public interface IPerson
{
void Say();
}
[Interceptor(typeof(LogInterceptor))]
public class Person : IPerson
{
public void Say()
{
Console.WriteLine("Person's Say Method is called!");
}
}
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("{0}:攔截{1}方法{2}前,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
invocation.Proceed();
Console.WriteLine("{0}:攔截{1}方法{2}后,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
}
}
static void Main(string[] args)
{
using (var container = new WindsorContainer())
{
container.Register(Component.For<Person, IPerson>());
container.Register(Component.For<LogInterceptor, IInterceptor>());
var person = container.Resolve<IPerson>();
person.Say();
}
Console.ReadKey();
}
非侵入式AOP
public interface IPerson
{
void Say();
}
public class Person : IPerson
{
public void Say()
{
Console.WriteLine("Person's Say Method is called!");
}
}
internal static class LogInterceptorRegistrar
{
public static void Initialize(WindsorContainer container)
{
container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
}
private static void Kernel_ComponentRegistered(string key, IHandler handler)
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(LogInterceptor)));
}
}
public class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("{0}:攔截{1}方法{2}前,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
invocation.Proceed();
Console.WriteLine("{0}:攔截{1}方法{2}后,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
}
}
static void Main(string[] args)
{
using (var container = new WindsorContainer())
{
container.Register(Component.For<IInterceptor, LogInterceptor>());//先注入攔截器
LogInterceptorRegistrar.Initialize(container);
container.Register(Component.For<IPerson, Person>());
var person = container.Resolve<IPerson>();
person.Say();
}
Console.ReadKey();
}
Autofac
Install-Package Autofac.Aop
通過特性標簽綁定
class LogInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("{0}:攔截{1}方法{2}前,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
invocation.Proceed();
Console.WriteLine("{0}:攔截{1}方法{2}后,", DateTime.Now.ToString("O"), invocation.InvocationTarget.GetType().BaseType, invocation.Method.Name);
}
}
public interface IPerson
{
void Say();
}
[Intercept(typeof(LogInterceptor))]
public class Person : IPerson
{
public void Say()
{
Console.WriteLine("Person's Say Method is called!");
}
}
啟用攔截器執行
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Person>().As<IPerson>().EnableInterfaceInterceptors();
builder.RegisterType<LogInterceptor>();
using (var container = builder.Build())
{
container.Resolve<IPerson>().Say();
}
Console.ReadLine();
}
或采用非侵入性方法(去掉class上的特性仍可以)
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Person>().As<IPerson>().EnableInterfaceInterceptors().InterceptedBy(typeof(LogInterceptor));
builder.RegisterType<LogInterceptor>();
using (var container = builder.Build())
{
container.Resolve<IPerson>().Say();
}
Console.ReadLine();
}
Unity
Unity默認提供了三種攔截器:TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor。
TransparentProxyInterceptor:代理實現基於.NET Remoting技術,它可攔截對象的所有函數。缺點是被攔截類型必須派生於MarshalByRefObject。
InterfaceInterceptor:只能對一個接口做攔截,好處時只要目標類型實現了指定接口就可以攔截。
VirtualMethodInterceptor:對virtual函數進行攔截。缺點是如果被攔截類型沒有virtual函數則無法攔截,這個時候如果類型實現了某個特定接口可以改用
Install-Package Unity.Interception
public class MyHandler : ICallHandler
{
public int Order { get; set; }//這是ICallHandler的成員,表示執行順序
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("方法執行前");
//這之前插入方法執行前的處理
var retvalue = getNext()(input, getNext);//在這里執行方法
//這之后插入方法執行后的處理
Console.WriteLine("方法執行后");
return retvalue;
}
}
public class MyHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new MyHandler();//返回MyHandler
}
}
public interface IPerson
{
void Say();
}
[MyHandler]
public class Person : IPerson
{
public virtual void Say()
{
Console.WriteLine("Person's Say Method is called!");
}
}
static void Main(string[] args)
{
using (var container = new UnityContainer())
{
container.AddNewExtension<Interception>();
//1.TransparentProxyInterceptor
//container.Configure<Interception>().SetInterceptorFor<IPerson>(new TransparentProxyInterceptor());
//2.InterfaceInterceptor (使用1,2,3均可,這種侵入性最小)
container.Configure<Interception>().SetInterceptorFor<IPerson>(new InterfaceInterceptor());
//3.VirtualMethodInterceptor
//container.Configure<Interception>().SetInterceptorFor<Person>(new VirtualMethodInterceptor());
container.RegisterType<IPerson, Person>();
container.Resolve<IPerson>().Say();
}
Console.ReadKey();
}
