测试代码链接
AOP简单了解
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP/OOP
区分
AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
上面的陈述可能过于理论化,举个简单的例子,对于“雇员”这样一个业务实体进行封装,自然是OOP/OOD的任务,我们可以为其建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP设计思想对“雇员”进行封装将无从谈起。
同样,对于“权限检查”这一动作片断进行划分,则是AOP的目标领域。而通过OOD/OOP对一个动作进行封装,则有点不伦不类。
换而言之,OOD/OOP面向名词领域,AOP面向动词领域。
关系
很多人在初次接触 AOP 的时候可能会说,AOP 能做到的,一个定义良好的 OOP 的接口也一样能够做到,我想这个观点是值得商榷的。AOP和定义良好的 OOP 的接口可以说都是用来解决并且实现需求中的横切问题的方法。但是对于 OOP 中的接口来说,它仍然需要我们在相应的模块中去调用该接口中相关的方法,这是 OOP 所无法避免的,并且一旦接口不得不进行修改的时候,所有事情会变得一团糟;AOP 则不会这样,你只需要修改相应的 Aspect,再重新编织(weave)即可。 当然,AOP 也绝对不会代替 OOP。核心的需求仍然会由 OOP 来加以实现,而 AOP 将会和 OOP 整合起来,以此之长,补彼之短。
传统的程序通常表现出一些不能自然地适合单一的程序模块或者是几个紧密相关的程序模块的行为,AOP 将这种行为称为横切,它们跨越了给定编程模型中的典型职责界限。横切行为的实现都是分散的,软件设计师会发现这种行为难以用正常的逻辑来思考、实现和更改。最常见的一些横切行为如下面这些:
日志记录,跟踪,优化和监控
事务的处理
持久化
性能的优化
资源池,如数据库连接池的管理
系统统一的认证、权限管理等
应用系统的异常捕捉及处理
针对具体行业应用的横切行为
概念简单总结:
OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统
类–砖头 系统–房子
类–细胞 系统–人
面向对象是非常适合做大型系统,面向对象是静态的,应对需求变化扩展的时候改动较大
AOP:面向切面编程 编程思想
在不破坏封装的前提下,去增加各种功能:非业务逻辑,是一些公共逻辑
是对OOP的有效补充,有了AOP之后,OOP也变得简单了
设计模式:在面向对象的基础上结合其他编程思想设计出灵活 可扩展 可重用 的架构
在上图中可以每个模块中共有的验证,异常,日志,缓存当成非业务逻辑,可以用AOP去实现这些非业务公共逻辑,让面向对象的业务封装变得更加的简单。利用AOP切面编程让非业务逻辑的扩展变得更加的灵活。
使用Unity实现AOP简单案例
NuGet包管理器安装Unity version=“5.8.6”
使用Unity实现AOP需要实现AOP的对象提供接口
AOP配置文件
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="aopContainer">
<extension type="Interception"/>
<register type="AOPConsoleApp.Model.IUserProcessor,AOPConsoleApp" mapTo="AOPConsoleApp.Model.UserProcessor,AOPConsoleApp">
<interceptor type="InterfaceInterceptor"/>
<interceptionBehavior type="AOPConsoleApp.UnityWay.ExceptionLoggingBehavior, AOPConsoleApp"/>
<interceptionBehavior type="AOPConsoleApp.UnityWay.CachingBehavior, AOPConsoleApp"/>
<interceptionBehavior type="AOPConsoleApp.UnityWay.LogBeforeBehavior, AOPConsoleApp"/>
<interceptionBehavior type="AOPConsoleApp.UnityWay.ParameterCheckBehavior, AOPConsoleApp"/>
<interceptionBehavior type="AOPConsoleApp.UnityWay.LogAfterBehavior2, AOPConsoleApp"/>
<interceptionBehavior type="AOPConsoleApp.UnityWay.LogAfterBehavior, AOPConsoleApp"/>
</register>
</container>
</containers>
</unity>
</configuration>
配置UnityContainer实现AOP动态代理
using AOPConsoleApp.Model;
using Microsoft.Practices.Unity.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;
namespace AOPConsoleApp
{
/// <summary>
/// 使用EntLib\PIAB Unity 实现动态代理
/// </summary>
public class UnityConfigAOP
{
public static void Show()
{
User user = new User()
{
Name = "caixukun",
Password = "123456789121231"
};
{
//通过Unity实例化对象
//IUnityContainer container = new UnityContainer();
//container.RegisterType<IUserProcessor, UserProcessor>();
//IUserProcessor processor = container.Resolve<IUserProcessor>();
//processor.RegUser(user);
}
{
//配置UnityContainer实现AOP动态代理
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);
Console.WriteLine(processor.GetUser(user));
Console.WriteLine(processor.GetUser(user));
}
}
}
}
非业务逻辑扩展代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;
namespace AOPConsoleApp.UnityWay
{
public class CachingBehavior : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
private static Dictionary<string, object> CachingBehaviorDictionary = new Dictionary<string, object>();
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("CachingBehavior");
string key = $"{input.MethodBase.Name}_{Newtonsoft.Json.JsonConvert.SerializeObject(input.Inputs)}";
if (CachingBehaviorDictionary.ContainsKey(key))
{
return input.CreateMethodReturn(CachingBehaviorDictionary[key]);//直接返还 断路器 不再往下
}
else
{
IMethodReturn result = getNext().Invoke(input, getNext);
if (result.ReturnValue != null)
CachingBehaviorDictionary.Add(key, result.ReturnValue);
return result;
}
}
public bool WillExecute
{
get { return true; }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;
namespace AOPConsoleApp.UnityWay
{
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
Console.WriteLine("ExceptionLoggingBehavior");
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 System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;
namespace AOPConsoleApp.UnityWay
{
public class LogAfterBehavior : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);//执行后面的全部动作
Console.WriteLine("LogAfterBehavior");
//Console.WriteLine(input.MethodBase.Name);
//foreach (var item in input.Inputs)
//{
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
//}
//Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);
return methodReturn;
}
public bool WillExecute
{
get { return true; }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;
namespace AOPConsoleApp.UnityWay
{
public class LogBeforeBehavior : IInterceptionBehavior
{
//public bool WillExecute => throw new NotImplementedException();
public bool WillExecute
{
get { return true; }
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("LogBeforeBehavior");
//Console.WriteLine(input.MethodBase.Name);
//foreach (var item in input.Inputs)
//{
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
//}
return getNext().Invoke(input, getNext);
}
}
}
using AOPConsoleApp.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Interception.InterceptionBehaviors;
using Unity.Interception.PolicyInjection.Pipeline;
namespace AOPConsoleApp.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位"));//抛出异常会终止后续的AOP
//throw new Exception("密码长度不能小于10位");
}
else
{
Console.WriteLine("参数检测无误");
return getNext().Invoke(input, getNext);
}
}
public bool WillExecute
{
get { return true; }
}
}
}