面向切面编程AOP
最开始接触AOP这个概念,是在大学Java课程中(具体哪本忘记了,JavaWeb?)接触到的。当时的理解就是,一个请求过来,自上而下,突然从中间切一刀。从那个图是这样理解的,文字描述的都忘记了。关于AOP的博客有好多,在工作中需要用到,我也是看着博客,外加视频学习来理解的。
http://wayfarer.cnblogs.com/articles/241012.html
这篇博客,写的还是蛮详细的。下面只是我自己的总结。
AOP不是一种设计模式,而是一种编程思想,和POP,OOP一样,是OOP的扩展,AOP的出现并不能代替OOP。
POP,面向过程编程:
符合逻辑思维,线性的处理问题,但是无法应对复杂的系统
OOP面向对象编程:
万物皆对象,对象交互完成功能,功能叠加成模块,模块组成系统,才有机会搭建复杂的大型的软件系统。
下面以一个例子来作为对比:
砖块--------墙---------房间---------大厦
类--------功能点------模块---------系统
砖块应该是稳定的,说明是静态,不变的。在程序开发的过程中,类确实会变化的,增加日志/异常/权限/缓存/事务等,只能修改类。
在GOF23种设计模式,应对变化的,核心套路是依赖抽象,细节就可以变化,但是只能替换整个对象,没办法把一个类动态改变。
AOP面向切面编程:
允许开发者动态的修改静态的OO模型,就像现实生活中对象在生命周期中会不断的改变自身。AOP是一种编程思想,是OOP思想的补充。
正式因为能够动态的扩展功能,所以在程序设计的时候,就可以有以下好处:
1、聚焦核心业务逻辑,权限/异常/缓存/事务,通过功能可以通过AOP方式添加,程序设计简单。
2、动态扩展,集中管理,代码复用,规范化。
下面,用装饰器模式,去实现一个AOP功能:
/// <summary> /// 装饰器模式实现静态代理 /// AOP 在方法前后增加自定义的方法 /// </summary> public class DecoratorAOP { public static void Show() { User user = new User() { Name = "bingle", 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; } 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("方法执行后"); } } }
实现AOP的多种方式:
1、静态实现----装饰器/代理模式
2、动态实现----Remoting/Castlet
3、静态植入---PostSharp(收费)----扩展编译工具,生成的加入额外代码
4、依赖注入容器的AOP扩展(Unity)
5、MVC的Filter---特性标机,然后该方法执行前后就多了逻辑
之前看到有的人认为,在.NET Core中的中间件,也是AOP的一种实现。也有一些人认为不是。博主认为,.NET Core中的中间件并不是AOP的一种实现。等后续随笔记载到中间件的时候,再去详细说明吧。
依赖注入容器的AOP扩展(扩展)
基于配置文件的Unity。
首先,用Nuget引入Unity想换的程序集
下面是配置文件:
<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"> <extension type="Interception"/> <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP"> <interceptor type="InterfaceInterceptor"/> <interceptionBehavior type="MyAOP.UnityWay.MonitorBehavior, 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>
使用EntLib\PIAB Unity 实现动态代理:
public class UnityConfigAOP { [Obsolete] public static void Show() { User user = new User() { Name = "bingle", Password = "1234567890123456789" }; //配置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"); IUserProcessor processor = container.Resolve<IUserProcessor>(); processor.RegUser(user); processor.GetUser(user); } }
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());//反射获取更多信息 } IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue); return methodReturn; } public bool WillExecute { get { return true; } } }
/// <summary> /// 不需要特性 /// </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());//反射获取更多信息 } 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; } } }
/// <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 = "Eleven" }); return getNext().Invoke(input, getNext); } public bool WillExecute { get { return true; } } }
/// <summary> /// 性能监控的AOP扩展 /// </summary> public class MonitorBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine(this.GetType().Name); string methodName = input.MethodBase.Name; Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); var methodReturn = getNext().Invoke(input, getNext);//后续逻辑执行 stopwatch.Stop(); Console.WriteLine($"{this.GetType().Name}统计方法{methodName}执行耗时{stopwatch.ElapsedMilliseconds}ms"); return methodReturn; } public bool WillExecute { get { return true; } } }