AOP
面向切面编程与 OOP
面向对象编程的关系 AOP
(Aspect-Oriented Programming
,面向方面编程),可以说是 OOP(Object-Oriented Programing
,面向对象编程)的补充和完善。
OOP
引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP
则显得无能为力。也就是说, OOP
允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting
)代码,在 OOP
设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而 AOP
技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect
”,即方面。
所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP
代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
使用“横切”技术,AOP
把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop
的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如 Avanade
公司的高级方案构架师 Adam Magee
所说,AOP
的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”
AOP
技术的实现主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。然而殊途同归,实现 AOP
的技术特性却是相同的。
装饰器模式实现静态代理 AOP
在方法的前后增加自定义的方法。详见:Decorator.Show()
方法,静态装饰器实现,并不推荐。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public static class Decorator { public static void Show ( ) { User user = new User() { Name = "John" , Password = "12345678" }; IUserProcessor processor = new UserProcessor(); Console.WriteLine("******使用普通方法完成注册******" ); processor.RegistUser(user); Console.WriteLine("******使用装饰器模式完成注册******" ); processor = new UserProcessorDecorator(processor); processor.RegistUser(user); } public class User { public string Name { get ; set ; } public string Password { get ; set ; } } public interface IUserProcessor { void RegistUser (User user ) ; } public class UserProcessor : IUserProcessor { public void RegistUser (User user ) { Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password} " ); } } public class UserProcessorDecorator : IUserProcessor { private IUserProcessor UserProcessor { get ; set ; } public UserProcessorDecorator (IUserProcessor processor ) { UserProcessor = processor; } public void RegistUser (User user ) { PreProceed(user); try { this .UserProcessor.RegistUser(user); } catch (Exception) { throw ; } PostProced(user); } private void PreProceed (User user ) { Console.WriteLine($"注册用户:{user.Name} 密码:{user.Password} 之前" ); } private void PostProced (User user ) { Console.WriteLine($"注册用户:{user.Name} 密码:{user.Password} 之后" ); } } }
使用 .Net Remoting/RealProxy
实现动态代理 详见 Proxy.Show()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 public static class Proxy { public static void Show ( ) { User user = new User() { Name = "John" , Password = "12345678" }; IUserProcessor processor = new UserProcessor(); Console.WriteLine("******使用普通方法完成注册******" ); processor.RegistUser(user); Console.WriteLine("******使用动态代理完成注册******" ); UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>(); userProcessor.RegistUser(user); } public class User { public string Name { get ; set ; } public string Password { get ; set ; } } public interface IUserProcessor { void RegistUser (User user ) ; } public class UserProcessor : MarshalByRefObject , IUserProcessor { public void RegistUser (User user ) { Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password} " ); } } public class MyRealProxy <T > : RealProxy { private T tTarget; public MyRealProxy (T target ) : base (typeof (T )) { this .tTarget = target; } public override IMessage Invoke (IMessage msg ) { PreProceed(msg); IMethodCallMessage callMessage = (IMethodCallMessage)msg; object returnValue = callMessage.MethodBase.Invoke(this .tTarget, callMessage.Args); PostProced(msg); return new ReturnMessage(returnValue, new object [0 ], 0 , null , callMessage); } private void PreProceed (IMessage msg ) { IMethodCallMessage callMessage = (IMethodCallMessage)msg; StringBuilder sbInfo = new StringBuilder(); if (callMessage.Args.Length > 0 ) { PropertyInfo[] props = callMessage.Args[0 ].GetType().GetProperties(); for (int i = 0 ; i < props.Length; i++) { sbInfo.Append($"{props[i].Name} :{props[i].GetValue(callMessage.Args[0 ], null )} " ); } } Console.WriteLine($"方法执行前:{sbInfo.ToString().TrimEnd()} " ); } private void PostProced (IMessage msg ) { IMethodCallMessage callMessage = (IMethodCallMessage)msg; StringBuilder sbInfo = new StringBuilder(); if (callMessage.Args.Length > 0 ) { PropertyInfo[] props = callMessage.Args[0 ].GetType().GetProperties(); for (int i = 0 ; i < props.Length; i++) { sbInfo.Append($"{props[i].Name} :{props[i].GetValue(callMessage.Args[0 ], null )} " ); } } Console.WriteLine($"方法执行后:{sbInfo.ToString().TrimEnd()} " ); } } public static class TransparentProxy { public static T Create <T >( ) { T instance = Activator.CreateInstance<T>(); MyRealProxy<T> proxy = new MyRealProxy<T>(instance); T transparentProxy = (T)proxy.GetTransparentProxy(); return transparentProxy; } } }
使用 Castle/DynamicProxy
实现动态代理 详见 CastleProxy.Show()
方法。(nuget
安装 Castle.DynamicProxy
或 Castle.Core
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 public class CastleProxy { public static void Show ( ) { User user = new User() { Name = "John" , Password = "12345678" }; IUserProcessor processor = new UserProcessor(); Console.WriteLine("******使用普通方法完成注册******" ); processor.RegistUser(user); Console.WriteLine("******使用动态代理完成注册******" ); ProxyGenerator generator = new ProxyGenerator(); MyInterceptor interceptor = new MyInterceptor(); processor = generator.CreateClassProxy<UserProcessor>(interceptor); processor.RegistUser(user); } public class User { public string Name { get ; set ; } public string Password { get ; set ; } } public interface IUserProcessor { void RegistUser (User user ) ; } public class UserProcessor : MarshalByRefObject , IUserProcessor { public virtual void RegistUser (User user ) { Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password} " ); } } public class MyInterceptor : IInterceptor { public void Intercept (IInvocation invocation ) { PreProceed(invocation); invocation.Proceed(); PostProced(invocation); } private void PreProceed (IInvocation invocation ) { StringBuilder sbInfo = new StringBuilder(); if (invocation.Arguments.Length > 0 ) { PropertyInfo[] props = invocation.Arguments[0 ].GetType().GetProperties(); for (int i = 0 ; i < props.Length; i++) { sbInfo.Append($"{props[i].Name} :{props[i].GetValue(invocation.Arguments[0 ], null )} " ); } } Console.WriteLine($"方法执行前:{sbInfo.ToString().TrimEnd()} " ); } private void PostProced (IInvocation invocation ) { StringBuilder sbInfo = new StringBuilder(); if (invocation.Arguments.Length > 0 ) { PropertyInfo[] props = invocation.Arguments[0 ].GetType().GetProperties(); for (int i = 0 ; i < props.Length; i++) { sbInfo.Append($"{props[i].Name} :{props[i].GetValue(invocation.Arguments[0 ], null )} " ); } } Console.WriteLine($"方法执行后:{sbInfo.ToString().TrimEnd()} " ); } } }
使用 EntLib/PIBA Unity
实现动态代理 详见 UnityAOP.Show()
方法。(nuget
安装Unity 4.0.1
与 Unity.Interception
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 public class UnityAOP { public static void Show ( ) { User user = new User() { Name = "John" , Password = "12345678" }; IUserProcessor processor = new UserProcessor(); Console.WriteLine("******使用普通方法完成注册******" ); processor.RegistUser(user); Console.WriteLine("******使用动态代理完成注册******" ); IUnityContainer container = new UnityContainer(); container.RegisterType<IUserProcessor, UserProcessor>(); processor = container.Resolve<IUserProcessor>(); processor.RegistUser(user); container.AddNewExtension<Interception>().Configure<Interception>().SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor()); processor = container.Resolve<IUserProcessor>(); processor.RegistUser(user); } #region 特性 public class UserHanlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler (IUnityContainer container ) { ICallHandler handler = new UserHandler() { Order = this .Order }; return handler; } } public class LogHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler (IUnityContainer container ) { ICallHandler handler = new LogHandler() { Order = this .Order }; return handler; } } public class ExceptionHandlerAttribute : HandlerAttribute { public override ICallHandler CreateHandler (IUnityContainer container ) { ICallHandler handler = new ExceptionHandler() { Order = this .Order }; return handler; } } public class AfterLogHandlerAttributeAttribute : HandlerAttribute { public override ICallHandler CreateHandler (IUnityContainer container ) { ICallHandler handler = new AfterLogHandler() { Order = this .Order }; return handler; } } #endregion #region 特性对应的行为 public class UserHandler : ICallHandler { public int Order { get ; set ; } public IMethodReturn Invoke (IMethodInvocation input, GetNextHandlerDelegate getNext ) { Console.WriteLine("this is the user handler." ); User user = input.Arguments[0 ] as User; Console.WriteLine($"regist user Name: {user.Name} Password: {user.Password} " ); if (string .IsNullOrWhiteSpace(user.Name)) { throw new Exception("user name can't be null, empty or white space." ); } if (string .IsNullOrWhiteSpace(user.Password) || user.Password.Length < 8 || user.Password.Length > 32 ) { throw new Exception("user password can't be null, empty or white space, and the password's length must between 8-32." ); } return getNext()(input, getNext); } } public class LogHandler : ICallHandler { public int Order { get ; set ; } public IMethodReturn Invoke (IMethodInvocation input, GetNextHandlerDelegate getNext ) { Console.WriteLine("this is the log handler." ); User user = input.Arguments[0 ] as User; Console.WriteLine($"Name: {user.Name} Password: {user.Password} " ); return getNext()(input, getNext); } } public class ExceptionHandler : ICallHandler { public int Order { get ; set ; } public IMethodReturn Invoke (IMethodInvocation input, GetNextHandlerDelegate getNext ) { IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine("this is the exception handler." ); User user = input.Arguments[0 ] as User; if (methodReturn.Exception == null ) { Console.WriteLine($"end regist user. Name: {user.Name} Password: {user.Password} don't have exception." ); } else { Console.WriteLine($"end regist user. Name: {user.Name} Password: {user.Password} have a exception: {methodReturn.Exception.Message} " ); } return methodReturn; } } public class AfterLogHandler : ICallHandler { public int Order { get ; set ; } public IMethodReturn Invoke (IMethodInvocation input, GetNextHandlerDelegate getNext ) { Console.WriteLine("this is the end log handler." ); User user = input.Arguments[0 ] as User; Console.WriteLine($"end regist user. Name: {user.Name} Password: {user.Password} " ); return getNext()(input, getNext); } } #endregion public class User { public string Name { get ; set ; } public string Password { get ; set ; } } [UserHanler(Order = 1), ExceptionHandler(Order = 3), LogHandler(Order = 2), AfterLogHandlerAttribute(Order = 5) ] public interface IUserProcessor { void RegistUser (User user ) ; void GetUser (User user ) ; } public class UserProcessor : IUserProcessor { public void GetUser (User user ) { throw new NotImplementedException(); } public void RegistUser (User user ) { Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password} " ); } } }
以上四种方式,前三种理解,第四种需要掌握。