- A+
本章将简单介绍下AOP面向切面编程。首先我们先来看些概念。
POP面向过程编程:符合逻辑思维,线性的处理问题-----无法应付复杂的系统。
OOP面向对象编程:
万物皆对象,对象交互完成功能,功能叠加成模块,模块组成系统,去搭建复杂的大型软件系统。
类却是会变化的,增加日志/异常/权限/缓存/事务,只能修改类?
只能替换整个对象,没办法把一个类动态改变。
GOF的23种设计模式,应对变化,核心套路是依赖抽象,细节就可以变化。
AOP面向切面编程:
是一种编程思想,是OOP思想的补充。
允许开发者动态的修改静态的OO模型,就像现实生活中对象在生命周期中会不断的改变自身。
正是因为能够动态的扩展功能,所以在程序设计时就可以有以下好处:
1、只需要聚焦核心业务逻辑,权限/异常/日志/缓存/事务等通用功能可以通过AOP方式添加,使程序设计变得更加简单。
2、功能动态扩展;集中管理;代码复用;规范化;
实现AOP的多种方式:
1、静态实现---装饰器模式/代理模式。
2、动态实现---Remoting/Castle(Emit)
3、静态织入---PostSharp(收费)---扩展编译工具,生成的加入额外代码。
4、依赖注入容器的AOP扩展(开发)
5、MVC的Filter---特性标记,然后该方法执行前/后就多了逻辑。
下面看一张图来辅助我们了解:
从图中一刀切过去将核心业务逻辑和我们的通用功能分离,这样的话我们只需要聚焦核心业务逻辑,权限/异常/日志/缓存/事务等通用功能可以通过AOP方式添加,使程序设计变得更加简单。
下面我们重点来看下代码如何实现,为了演示此处我们使用VS2017建个控制台项目MyAOP,目标框架为:.NET Framework 4.6.1,如下所示:
一、代理模式实现静态代理(静态实现AOP)
using System; namespace MyAOP { /// <summary> /// 用户类 /// </summary> public class User { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } } }
using System; namespace MyAOP { /// <summary> /// 代理模式实现静态代理 /// AOP 在方法前后增加自定义的方法 /// </summary> public class ProxyAOP { public static void Show() { User user = new User() { Name = "浪子天涯", Password = "123456" }; 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> private void BeforeProceed(User user) { Console.WriteLine("方法执行前"); } /// <summary> /// 业务逻辑之后 /// </summary> private void AfterProceed(User user) { Console.WriteLine("方法执行后"); } } } }
看下调用ProxyAOP.Show()的结果:
二、装饰器模式实现静态代理(静态实现AOP)
using System; namespace MyAOP { /// <summary> /// 装饰器模式实现静态代理 /// AOP 在方法前后增加自定义的方法 /// </summary> public class DecoratorAOP { public static void Show() { User user = new User() { Name = "浪子天涯", Password = "88888888" }; 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> private void BeforeProceed(User user) { Console.WriteLine("方法执行前"); } /// <summary> /// 业务逻辑之后 /// </summary> private void AfterProceed(User user) { Console.WriteLine("方法执行后"); } } } }
看下调用DecoratorAOP.Show()的结果:
3、使用Unity容器实现AOP
首先来看下项目目录结构:
需要从NuGet上引用如下程序包:
核心业务逻辑:
using System; namespace MyAOP.UnityWay { public interface IUserProcessor { //[Obsolete] //此处可扩展 void RegUser(User user); User GetUser(User user); } }
using System; namespace MyAOP.UnityWay { public class UserProcessor : IUserProcessor { public void RegUser(User user) { Console.WriteLine("用户已注册。"); } public User GetUser(User user) { return user; } } }
AOP扩展:
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { /// <summary> /// 缓存AOP扩展 /// </summary> public class CachingBehavior : IInterceptionBehavior { /// <summary> /// 固定写法 /// </summary> 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); } /// <summary> /// 固定写法 /// </summary> public bool WillExecute { get { return true; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { 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; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { 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; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { /// <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; } } } }
using System; using System.Collections.Generic; using System.Diagnostics; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { /// <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; } } } }
using System; using System.Collections.Generic; using Unity.Interception.InterceptionBehaviors; using Unity.Interception.PolicyInjection.Pipeline; namespace MyAOP.UnityWay { 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) { return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位")); } else { Console.WriteLine("参数检测无误"); return getNext().Invoke(input, getNext); } } public bool WillExecute { get { return true; } } } }
Unity.config配置文件:
<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>
注意:编译时需要将配置文件输出到bin/debug目录下,设置如下所示:
使用如下:
using System; using System.IO; using System.Configuration; using Microsoft.Practices.Unity.Configuration; using Unity; namespace MyAOP.UnityWay { public class UnityConfigAOP { public static void Show() { User user = new User() { Name = "浪子天涯", Password = "12345678910" }; //配置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); } } }
调用UnityConfigAOP.Show()的结果如下:
Demo源码:
链接:https://pan.baidu.com/s/147Veb1fU49sT5bcEbgrERw 提取码:j5ml
此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13532063.html
版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!