一.AOP概述:
面向切面编程。采用“横切”的思想,将软件系统的系统功能和业务功能分开。
系统功能主要有:
1.缓存模块:用于缓存数据,与系统业务功能关系不大,用于提升系统性能。当数据请求过来时,是否要从缓存读取,当缓存没有数据时,
是否要将获取到的数据放入缓存,以便下次数据请求时从缓存读取。比较常用的缓存工具有monogodb,redis。
2.验证模块:判断当前用户是否有获取该条数据 或者执行 该操作的权限。
3.日志模块:收集当前用户的操作痕迹,或者记录系统出现的问题,后期可进行大数据行为分析。
业务功能:系统处理用户请求的正常逻辑功能。
http请求过来后,会先经过系统功能的横切拦截,才会到业务功能处理请求。AOP具体过程如下图所示:
二、AOP实现:
https://github.com/dotnetcore/AspectCore-Framework。
要使用该框架,可通过Nuget 将 AspectCore.Extensions.DependencyInjection 引用到项目中,可实现日志拦截和缓存拦截,该框架是基于IOC容器的。
这里,我用控制台程序来演示:首先,先nuget 引用 AspectCore.Extensions.DependencyInjection。
1.程序入口:
class Program
{
static void Main(string[] args)
{
//创建用于注册服务的IOC容器 ServiceCollection
ServiceCollection services = new ServiceCollection();
//在容器中 注册服务
services.ConfigureDynamicProxy();
services.AddScoped<IMySql, MySql>();
//创建ServiceProvider,用于获取服务。
var provider = services.BuildDynamicProxyProvider();
//获取服务。
var mysql = provider.GetService<IMySql>();
//执行服务。
var msg=mysql.GetById(10);
//第一次去数据,从业务逻辑取数据
var value = mysql.GetData("hehe");
Console.WriteLine(value);
//第二次去数据,从缓存取
value = mysql.GetData("hehe");
Console.WriteLine(value);
Console.ReadKey();
Console.WriteLine("Hello World!");
}
}
2.系统功能 切面部分(AOP):
日志切面:
/// <summary>
/// 日志模块:(日志切面,日志AOP)
/// </summary>
public class MyLogInterceptorAttribute : AbstractInterceptorAttribute
{
/// <summary>
///
/// </summary>
/// <param name="context">委托的参数,这里传递的是 GetById 方法</param>
/// <param name="next">委托,委托的动作要看具体传进来的方法的动作是什么</param>
/// <returns></returns>
public override Task Invoke(AspectContext context, AspectDelegate next)
{
Console.WriteLine("开始记录日志.......");
//var aa = context;
//var bb = next;
var task = next(context);//从这里开始执行具体的方法。这里执行的是 GetById;
Console.WriteLine("结束记录日志.......");
return task;
}
}
缓存切面:
public class MyCacheInterceptorAttribute : AbstractInterceptorAttribute
{
//用于模拟缓存
private Dictionary<string, string> CacheDic = new Dictionary<string, string>();
/// <summary>
///
/// </summary>
/// <param name="context">委托的参数,这里传递的是 GetById 方法</param>
/// <param name="next">委托,委托的动作,要看具体传进来的方法的动作是什么</param>
/// <returns></returns>
public override Task Invoke(AspectContext context, AspectDelegate next)
{
//获取 传递过来的AspectContext,即传进来的方法 的参数。
var cacheKey = string.Join(",", context.Parameters);
//从缓存去数据。如果缓存有,则返回
if (CacheDic.ContainsKey(cacheKey))
{
context.ReturnValue = CacheDic[cacheKey].ToString();
return Task.CompletedTask;
}
//缓存没有,从业务逻辑取数据,去到数据后,将数据放入缓存
var task = next(context);
var cacheValue = context.ReturnValue.ToString();
CacheDic.Add(cacheKey, "From cache:"+cacheValue);
return task;
}
}
3.业务功能部分:
public interface IMySql
{
string GetById(int id);
string GetData(string key);
}
public class MySql : IMySql
{
[MyLogInterceptor] //日志切面
public string GetById(int id)
{
var msg = $"已经获取到ID为{id}的数据";
Console.WriteLine(id);
return msg;
}
[MyCacheInterceptor] //缓存切面
public string GetData(string key)
{
return "获取数据";
}
}