AOP
AOP(面向切面编程)
软件设计因为引入面向对象思想而逐渐变得丰富起来。“一切皆为对象”的精义,使得程序世界所要处理的逻辑简化,开发者可以用一组对象以及这些对象之间的关系将软件系统形象地表示出来。而从对象的定义,进而到模块,到组件的定义,利用面向对象思想的封装、继承、多态的思想,使得软件系统开发可以向搭建房屋那样,循序渐进,从砖石到楼层,进而到整幢大厦的建成。应用面向对象思想,在设计规模更大、逻辑更复杂的系统时,开发周期反而能变的更短。自然其中,需要应用到软件工程的开发定义、流程的过程控制,乃至于质量的缺陷管理。但从技术的细节来看,面向对象设计技术居功至伟。然而,面向对象设计的唯一问题是,它本质是静态的,封闭的,任何需求的细微变化都可能对开发进度造成重大影响。
可能解决该问题的方法是设计模式。GOF将面向对象软件的设计经验作为设计模式纪录下来,它使人们可以更加简单方便地复用成功的设计和体系结构,帮助开发人员做出有利于系统复用的选择。设计模式解决特定的设计问题,使面向对象设计更灵活、优雅,最终复用性更好。然而,设计模式虽然给了我们设计的典范与准则,通过最大程度的利用面向对象的特性,诸如利用继承、多态,对责任进行分离、对依赖进行倒置,面向抽象,面向接口,最终设计出灵活、可扩展、可重用的类库、组件,乃至于整个系统的架构。在设计的过程中,通过各种模式体现了对象的行为,暴露的接口,对象间关系,以及对象分别在不同层次中表现出来的形态。然而鉴于对象封装的特殊性,“设计模式”的触角始终在接口与抽象中大做文章,而对于对象内部则无能为力。
AOP正好可以解决这一问题。它允许开发者动态地修改静态的OO模型,构造出一个能够不断增长以满足新增需求的系统,就象现实世界中的对象会在其生命周期中不断改变自身,应用程序也可以在发展中拥有新的功能。AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的行为封装到一个可重用模块,并将其名为“Aspect”,即方面。
所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等。
主要意图:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
结论:将系统的某一个功能提取出来,作为单独的模块,只负责完成自己的那一部分功能,仅此而已。可以有效降低系统各部分之间的耦合性
按照AOP思想的方式:
a 装饰器模式/代理模式 静态实现
b 动态实现 (Remoting)(Emit)
c 通过Unity 支持AOP
示例1:通过Unity实现支持Aop,大部分都是通过这个方法,但是前提是引用Unity相关的dll
下面是配置文件信息:
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/> <!--Microsoft.Practices.Unity.Configuration.UnityConfigurationSection--> </configSections> <unity> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension,
Unity.Interception.Configuration"/> <containers> <container name="aopContainer"> <!--有这个节点表明这个配置文件支持AOP--> <extension type="Interception"/> <!-- MyAOP.UnityWay.IUserProcessor:指的是使用name为aopContainer这个container节点的接口空间名, 比如说使用的时候 : configSection.Configure(container, "aopContainer"); IUserProcessor processor = container.Resolve<IUserProcessor>(); IUserProcessor接口的全名称,就是MyAOP.UnityWay.IUserProcessor, 而MyAOP表示这个接口所在的程序或者exe就是是MyAOP。 mapTo里面的信息是指继承IUserProcessor这个接口的类。 --> <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP"> <!--InterfaceInterceptor:表示基于接口来扩展的,还有其他方式,--> <interceptor type="InterfaceInterceptor"/> <!--下面这些都是扩展的方法处理,注意,在调用真正的方法之前,会按照顺序依次执行这些类里的方法, --> <interceptionBehavior type="MyAOP.UnityWay.MoniterBehavior, MyAOP"/> <interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/> <interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/> <interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/> <interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/> <interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/> </register> </container> </containers> </unity> </configuration>
文件位置:
UnityConfigAOP:
/// <summary> /// /// 使用EntLib\PIAB Unity 实现动态代理 /// /// </summary> public class UnityConfigAOP { public static void Show() { User user = new User() { Name = "Richard", Password = "1234567890123456789" }; #region 配置UnityContainer 这部分就是个固定写法 IUnityContainer container = new UnityContainer(); ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection configSection =
(UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); configSection.Configure(container, "aopContainer"); #endregion IUserProcessor processor = container.Resolve<IUserProcessor>(); // 注意,现在默认的是继承IUserProcessor这个类的实现类UserProcessor里所有的方法都要把每个注册的AOP都走一遍 // 如果不想让某个函数走AOP或则不想走某一个AOP,可以在具体的方法前加上特性来进行处理。 // 如果想在真正执行RegUser方法之前做一些特殊处理,可以在配置文件中注册的第一个类中做处理, // 在执行 getNext().Invoke(input, getNext)这段代码之前执行想要的逻辑。 // 同理,想在执行完成RegUser方法之后又执行特殊的操作,可以在配置文件注册的aop方法中最后一个类里处理, // 当然,也可以直接在第1个里处理,getNext().Invoke(input, getNext)执行之后来处理RegUser调用完成后的任务 // 比如说这个配置文件,最后一个类LogAfterBehavior的Invoke方法中,执行getNext()(input, getNext)完成后做逻辑处理。 processor.RegUser(user); //同上 processor.GetUser(user); } }
IUserProcessor
namespace MyAOP.UnityWay { public interface IUserProcessor { void RegUser(User user); User GetUser(User user); } }
实现类:
// 通过IOC 依赖注入支持扩展AOP public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用户已注册。"); //throw new Exception("11"); } public User GetUser(User user) { return user; } }
下面是注册的方法:
/// <summary> /// 不需要特性 /// </summary> public class MoniterBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } /// <summary> /// input是传入的参数 /// </summary> /// <param name="input"></param> /// <param name="getNext">通过这个调用后续注册的方法</param> /// <returns></returns> public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // 这是第一个注册的方法,所以可以在这儿添加方法之前的逻辑 var query = getNext().Invoke(input, getNext); // 后面所有注册的AOP方法和要真正执行的方法都执行完成后,也可以在这里做后续处理。 stopwatch.Stop(); Console.WriteLine($"执行耗时:{stopwatch.ElapsedMilliseconds} ms"); return query; } public bool WillExecute { get { return true; } } } /// <summary> /// 不需要特性 /// /// 必须实现IInterceptionBehavior /// </summary> public class LogBeforeBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("LogBeforeBehavior"); foreach (var item in input.Inputs) { Console.WriteLine(item.ToString());//反射获取更多信息 } var query = getNext().Invoke(input, getNext); //下一个节点的方法已经执行完毕 //在这里计入方法执行后的逻辑 return query; } public bool WillExecute { get { return true; } } } /// <summary> /// 不需要特性 /// </summary> public class CachingBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("CachingBehavior"); //input.Target.GetType().GetCustomAttributes() // 通过这个可以判断调用的是哪个方法 if (input.MethodBase.Name.Equals("GetUser")) return input.CreateMethodReturn(new User() { Id = 234, Name = "Richard" }); return getNext().Invoke(input, getNext); } public bool WillExecute { get { return true; } } } public class ExceptionLoggingBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("ExceptionLoggingBehavior"); IMethodReturn methodReturn = getNext()(input, getNext); if (methodReturn.Exception == null) { Console.WriteLine("无异常"); } else { Console.WriteLine($"异常:{methodReturn.Exception.Message}"); } return methodReturn; } public bool WillExecute { get { return true; } } } public class LogAfterBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("LogAfterBehavior"); foreach (var item in input.Inputs) { Console.WriteLine(item.ToString());//反射获取更多信息 } // 因为在配置文件里,这个类是在最后一个,所以是最后执行的, // 所以在这里执行下面的方法,会真正的执行要调用的那个方法了,比如RegUser或者GetUser IMethodReturn methodReturn = getNext()(input, getNext); // 如果想要在执行完真正的方法最后还要做一些处理的话,就可以在下面接着写 Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue); return methodReturn; } public bool WillExecute { get { return true; } } } public class ParameterCheckBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("ParameterCheckBehavior"); //通过特性校验 User user = input.Inputs[0] as User; if (user.Password.Length < 10) { //throw new Exception(); return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位")); } else { Console.WriteLine("参数检测无误"); return getNext().Invoke(input, getNext); } } public bool WillExecute { get { return true; } } }
其中IOC,AOP,依赖注入的关系是:通过IOC 依赖注入支持扩展AOP
示例2:通过装饰器模式来实现AOP功能
namespace MyAOP { /// <summary> /// 装饰器模式实现静态代理 /// AOP 在方法前后增加自定义的方法 /// </summary> public class DecoratorAOP { public static void Show() { User user = new User() { Name = "Richard", Password = "123123123123" }; IUserProcessor processor = new UserProcessor(); processor.RegUser(user); Console.WriteLine("***************"); processor = new UserProcessorDecorator(processor); // 装饰器模式中的这个方法来扩展功能 processor.RegUser(user); } public interface IUserProcessor { void RegUser(User user); } public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password); } } /// <summary> /// 装饰器的模式去提供一个AOP功能 /// </summary> public class UserProcessorDecorator : IUserProcessor { private IUserProcessor _UserProcessor { get; set; } public UserProcessorDecorator(IUserProcessor userprocessor) { this._UserProcessor = userprocessor; } /// <summary> /// 在装饰器类里重新实现这个方法 /// </summary> /// <param name="user"></param> public void RegUser(User user) { BeforeProceed(user); this._UserProcessor.RegUser(user); AfterProceed(user); } /// <summary> /// 业务逻辑之前 /// </summary> /// <param name="user"></param> private void BeforeProceed(User user) { Console.WriteLine("方法执行前"); } /// <summary> /// 业务逻辑之后 /// </summary> /// <param name="user"></param> private void AfterProceed(User user) { Console.WriteLine("方法执行后"); } } } }
调用:
DecoratorAOP.Show();
示例3:代理模式实现AOP功能
/// <summary> /// 代理模式实现静态代理 /// AOP 在方法前后增加自定义的方法 /// </summary> public class ProxyAOP { public static void Show() { User user = new User() { Name = "Richard", Password = "123123123123" }; IUserProcessor processor = new UserProcessor(); processor.RegUser(user); Console.WriteLine("***************"); //代理模式实现,和装饰器不同的是不在构造函数里传参数 processor = new ProxyUserProcessor(); processor.RegUser(user); } public interface IUserProcessor { void RegUser(User user); } public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password); } } /// <summary> /// 代理模式去提供一个AOP功能 /// </summary> public class ProxyUserProcessor : IUserProcessor { private IUserProcessor _UserProcessor = new UserProcessor(); public void RegUser(User user) { BeforeProceed(user); this._UserProcessor.RegUser(user); AfterProceed(user); } /// <summary> /// 业务逻辑之前 /// </summary> /// <param name="user"></param> private void BeforeProceed(User user) { Console.WriteLine("方法执行前"); } /// <summary> /// 业务逻辑之后 /// </summary> /// <param name="user"></param> private void AfterProceed(User user) { Console.WriteLine("方法执行后"); } } }
调用:
class Program { static void Main(string[] args) { ProxyAOP.Show(); } }
示例4:通过remoting实现动态代理
/// <summary> /// 使用.Net Remoting/RealProxy 实现动态代理 /// 局限在业务类必须是继承自MarshalByRefObject类型 /// /// 下面的写法是一个固定的套路 /// </summary> public class RealProxyAOP { public static void Show() { User user = new User() { Name = "Richard", Password = "123456" }; UserProcessor processor = new UserProcessor(); processor.RegUser(user); Console.WriteLine("*********************"); UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>(); userProcessor.RegUser(user); } /// <summary> /// 真实代理 /// </summary> /// <typeparam name="T"></typeparam> public class MyRealProxy<T> : RealProxy { private T tTarget; public MyRealProxy(T target) : base(typeof(T)) { this.tTarget = target; } public override IMessage Invoke(IMessage msg) { BeforeProceede(msg);//Log try-catch IMethodCallMessage callMessage = (IMethodCallMessage)msg; object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args); AfterProceede(msg); return new ReturnMessage(returnValue, new object[0], 0, null, callMessage); } public void BeforeProceede(IMessage msg) { Console.WriteLine("方法执行前可以加入的逻辑"); } public void AfterProceede(IMessage msg) { Console.WriteLine("方法执行后可以加入的逻辑"); } } /// <summary> /// 透明代理 /// </summary> public static class TransparentProxy { public static T Create<T>() { T instance = Activator.CreateInstance<T>(); MyRealProxy<T> realProxy = new MyRealProxy<T>(instance); T transparentProxy = (T)realProxy.GetTransparentProxy(); return transparentProxy; } } public interface IUserProcessor { void RegUser(User user); } /// <summary> /// 必须继承自MarshalByRefObject父类,否则无法生成 /// </summary> public class UserProcessor : MarshalByRefObject, IUserProcessor { public void RegUser(User user) { Console.WriteLine("用户已注册。用户名称{0} Password{1}", user.Name, user.Password); } } }
示例5: 使用Castle\DynamicProxy 实现动态代理
/// <summary> /// 使用Castle\DynamicProxy 实现动态代理 /// 方法必须是虚方法 /// </summary> public class CastleProxyAOP { public static void Show() { User user = new User() { Name = "Richard", Password = "123456" }; ProxyGenerator generator = new ProxyGenerator(); MyInterceptor interceptor = new MyInterceptor(); UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor); userprocessor.RegUser(user); } public interface IUserProcessor { void RegUser(User user); } public class UserProcessor : IUserProcessor { /// <summary> /// 必须带上virtual 否则无效~ /// </summary> /// <param name="user"></param> public virtual void RegUser(User user) { Console.WriteLine($"用户已注册。Name:{user.Name},PassWord:{user.Password}"); } } public class MyInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { PreProceed(invocation); invocation.Proceed();//就是调用原始业务方法 PostProceed(invocation); } public void PreProceed(IInvocation invocation) { Console.WriteLine("方法执行前"); } public void PostProceed(IInvocation invocation) { Console.WriteLine("方法执行后"); } } }