引用地址:http://www.tuicool.com/articles/Ffi22e
引用地址:http://www.cnblogs.com/gaochundong/archive/2013/06/01/3113165.html
1.aop简介
AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。 OOP是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等来定义彼此的关系;AOP是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即可。 AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。在OOP的世界中,程序都是通过类和接口组织的,使用它们实现程序的核心业务逻辑是十分合适。但是对于实现横切关注点(跨越应用程序多个模块的功能需求)则十分吃力,比如日志记录,验证等2..NET中的aop
在.NET中,实现AOP有多种方法,一种方式是采用编译后处理方式,例如PostSharp,在编译后,PostSharp通过修改IL代码来诸如横切代码,相反地,对象拦截是在运行时执行的,比如,unity,spring.net等,这样也意味着会有一些限制,下面将对.net中实现aop的方式分开来说:
unity实现aop(本文)
spring.net实现aop
PostSharp实现aop
Unity默认提供了三种拦截器来实现aop:TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor
TransparentProxyInterceptor:代理实现基于.NET Remoting技术,它可拦截对象的所有函数。缺点是被拦截类型必须派生于MarshalByRefObject
InterfaceInterceptor:只能对一个接口做拦截,好处时只要目标类型实现了指定接口就可以拦截
VirtualMethodInterceptor:对virtual函数进行拦截。缺点是如果被拦截类型没有virtual函数则无法拦截,这个时候如果类型实现了某个特定接口可以改用InterfaceInterceptor
下面的表述是基于动态代理来实现aop
1)工作原理
当从Unity容器请求目标对象时,将不会获取到已配置的类的实例,实际上,将得到一个动态生成的代理对象,或者一个衍生类,如果调用代理对象的一个方法,将可以在被调用方法执行前或执行后执行一些额外行为的代码。那些定义行为的类需要实现ICallHandler接口。通过这些行为定义,我们可以访问方法调用的参数列表,可以吞噬异常,或者可以返回自定义的异常。原理图如下所示:
附带提一下,在不使用Unity容器的条件下,也是可以使用Unity拦截器的
2)对unity的引用
unity实现ioc需要引用:microsoft.practices.unity.configuration.dll
microsoft.practices.unity.dll
unity实现aop需要引用:
microsoft.practices.unity.interception.configuration.dll
microsoft.practices.unity.interception.dll
3)示例:将异常和方法调用参数列表记录到日志中
在下面的示例中,我们将创建两个自定义的行为,都实现了ICallHandler接口:
- LoggerCallHandler:将方法调用参数列表记录到日志中。
- ExceptionLoggerCallHandler:将方法调用参数列表和异常信息及调用栈记录到日志中。
ExceptionLoggerCallHandler定义如下:
1 internal class ExceptionLoggerCallHandler : ICallHandler 2 { 3 public IMethodReturn Invoke( 4 IMethodInvocation input, GetNextHandlerDelegate getNext) 5 { 6 IMethodReturn result = getNext()(input, getNext); 7 if (result.Exception != null) 8 { 9 Console.WriteLine("ExceptionLoggerCallHandler:"); 10 Console.WriteLine("\tParameters:"); 11 for (int i = 0; i < input.Arguments.Count; i++) 12 { 13 var parameter = input.Arguments[i]; 14 Console.WriteLine( 15 string.Format("\t\tParam{0} -> {1}", i, parameter.ToString())); 16 } 17 Console.WriteLine(); 18 Console.WriteLine("Exception occured: "); 19 Console.WriteLine( 20 string.Format("\tException -> {0}", result.Exception.Message)); 21 22 Console.WriteLine(); 23 Console.WriteLine("StackTrace:"); 24 Console.WriteLine(Environment.StackTrace); 25 } 26 27 return result; 28 } 29 30 public int Order { get; set; } 31 }
为了将行为应用到方法上,我们需要创建相应的HandlerAttribute来创建行为的实例。
1 internal class ExceptionLoggerAttribute : HandlerAttribute 2 { 3 public override ICallHandler CreateHandler(IUnityContainer container) 4 { 5 return new ExceptionLoggerCallHandler(); 6 } 7 }
在这个示例中,我们创建一个简单的计算器类。同时为了使用接口拦截功能,我们还需创建一个接口类型,这样才能应用指定的行为:
1 public interface ICalculator 2 { 3 [Logger] 4 int Add(int first, int second); 5 6 [ExceptionLogger] 7 int Multiply(int first, int second); 8 }
计算器类的实现还和常规的一样。现在我们需要配置Unity容器:
1 IUnityContainer container = new UnityContainer(); 2 container.AddNewExtension<Interception>(); 3 container 4 .RegisterType<ICalculator, Calculator>() 5 .Configure<Interception>() 6 .SetInterceptorFor<ICalculator>(new InterfaceInterceptor()); 7 8 // Resolve 9 ICalculator calc = container.Resolve<ICalculator>(); 10 11 // Call method 12 calc.Add(1, 2);
当在容器上通过调用Resolve方法来尝试获得一个Calculate类的实例时,将会得到一个代理类实例。它的名字可能类似于 ‘DynamicModule.ns.Wrapped_ICalculator_83093f794c8d452e8af4524873a017de’。当调用此包装类的某个方法时,CallHandlers将会被执行。
总结
Unity并不提供一个完整的AOP框架,因此使用它会有一些限制。但不管怎样,使用Unity对象拦截功能来实现一些基本的AOP需求已经足够了。