首页 技术 正文
技术 2022年11月6日
0 收藏 671 点赞 217 浏览 9235 个字

引言

何为AOP,在软件开发中,总是听到这个AOP这个词语,但是何为AOP呢,AOP全称是Aspect Oriented Programming,中文译为面向切面编程,什么意思呢,即我们的应用程序在运行的时候,我们在调用方法的时候,我们当前这个父类方法需要调用下面某个类的方法,等待这个方法给我们返回一个结果或者不返回,那这样的过程我们可以抽象的理解为自上而下,然后在自下而上,那AOP的概念我们就可以理解为在这个自上而下,和自下而上的过程中我们,我们实现了一层拦截,横插了一个处理程序,用来实现对方法和方法之间调用的一个拦截,可以实现自上而下,经过我们的AOP层面的代码,以及自下而上的时候 经过我们的AOP代码,在这个AOP层面,我们可以实现对程序的日志记录,异常处理,参数验证等等的一些常规操作。

实现方式

Aop的实现方式,大体是分为两个版本一个是不同框架下的实现方式,不同平台就是Framework下面的实现方式,还有一种是Core下面的实现方式,这里我们主要讲这两种,第二个实现方式下面是两个通用的实现方式,一种是基于IL的形式去实现,还有一种是基于内存的形式的实现,这里不太对这两种进行过多的讲解,后续会写一个使用IL去实现AOP的代码,这里主要讲FrameWork和Core框架下如何实现AOP代理的两种比较简单的方法。

frameWork

在framework的框架下,可以使用RealProxy类来实现静态代理的的aop,需要自己去继承RealProxy这个类,然后实现Invoke的抽象方法,即可实现Aop的实现,接下来我们看代码,

   public class DynamicProxy<T> : RealProxy
{
public T Instance = default;
public IInterceptor Interceptor;
public DynamicProxy():base(typeof(T))
{ }
public T GetInstance< Target, TInterceptor>() where TInterceptor: IInterceptor where Target: class,T
{
var result = this.GetTransparentProxy();
Instance = Activator.CreateInstance<Target>() ;
Interceptor = Activator.CreateInstance<TInterceptor>();
return (T)result;
}
public override IMessage Invoke(IMessage msg)
{
var methodMsg = msg as IMethodCallMessage;
try
{
if (methodMsg!=null)
{
var methodInfo = methodMsg.MethodBase as MethodInfo;
if (Interceptor != null)
{
Interceptor.BeforeEvent(methodMsg.MethodBase, methodMsg.InArgs);
}
var result= methodMsg.MethodBase.Invoke(Instance, methodMsg.InArgs);
if (Interceptor != null)
{
Interceptor.AfterEvent(methodMsg.MethodBase, result);
}
return new ReturnMessage(result, null, 0,
methodMsg.LogicalCallContext, methodMsg);
}
}
catch (Exception ex)
{
if (Interceptor != null)
{
Interceptor.ExceptionEvent(ex, methodMsg.MethodBase);
}
}
return new ReturnMessage(null, null, 0,
methodMsg.LogicalCallContext, methodMsg);
}
}
public interface IBase
{
string GetName();
}
public class BaseModel : IBase
{
public string GetName()
{
return Guid.NewGuid().ToString();
}
}

使用方式

            var proxy = new DynamicProxy<IBase>();
var ins=proxy.GetInstance<BaseModel,TestInterceptor>();
var result=ins.GetName();

我们在需要代理的对象的时候,我们传入了这个对象的继承的类型,在构造函数调用了RealProxy的构造方法传入我们需要代理的类型Type,然后在这里我写了一个创建对象以及设置拦截器的一个方法,可以看到在这个方法里,我们获取到了这个泛型T的静态代理的对象,这是我们要返回给上一层的,此处是我们创建的代理对象,在下面我们有创建了一个这个Target的对象,很多人就有些疑惑了,为什么同一类型的对象我们需要创建两次呢,这里呢是因为,如果我们同意的去使用这个静态的代理作为我们的Instance的话,那在Invoke方法里,我们调用我们调用的GetName的方法的Invoke的时候,会造成一个死循环的一个操作,就是不停的去GetName,也就不停止的走我们重写的Invoke的方法,这里,就起到了一个隔离作用,简单来说,就是上层对象需要将一个类型代理,走到我们的GetInstance方法中去,我们给他返回这个代理的对象,然后我们类内部同时有一个未被代理的对象在创建出来,这样我们的类有一个没被代理的实例,这样在代理的对象调用GetName的时候就可以走到我们的Invoke的方法中去,我们在执行GetName的方法时候我们使用Instance实例去承载我们所调用的方法,获取到结果之后在返回到调用的上方去,就类似于桥接的方式,我调用了A的GetName方法,但是在代理层面有一个B的实例,实际上我们是调用的是B的GetName的方法,而且GetInstance方法里面的返回必须是代理的对象,不然是不会走到Invoke方法中去,从而没办法实现拦截。

可以看到我们在GetInstance的时候我们也创建了我们的拦截器的实例,再看我们的Invoke方法,我们在方法的执行前,执行后,以及异常的时候我们分别调用了拦截器的BeforeEvent,AfterEvent以及ExceptionEvent方法,分别去传入我们的执行前后,异常等信息。

Net Core

在net core框架出来之后呢,代理方面也是有了一个改动,在fw版本下可以使用RealProxy实现AOP的功能,但是由于其性能方面以及其他方面的原因,core并不支持RealProxy,以及Core是不支持fw版本中的Remoting的,所以Core是以另一种方式支持代理去实现AOP的功能,其性能以及使用起来大大简化了RealProxy的功能,并且如果非面向抽象开发的前提下,RealProxy代理还需要继承MarshalByRefObject这个抽象接口,导致代理的对象调用方法的时候,过于依赖MarshalByRefObject,.方法名称的时候是可以看到基类的方法,这对我们来说很不友好,所以Core版本引入了DispatchProxy的类来实现代理,这个类同RealProxy一样是个抽象类,也必须实现Invoke方法。

 /// <summary>
/// Aop Proxy
/// </summary>
public class DynamicProxy : DispatchProxy
{
/// <summary>
/// 执行方法接口
/// </summary>
private IInterceptor interceptor { get; set; }
/// <summary>
/// 具体类型
/// </summary>
private object service { get; set; }
/// <summary>
/// 创建代理
/// </summary>
/// <param name="targetType"></param>
/// <param name="interceptor"></param>
/// <param name="serviceParameter"></param>
/// <returns></returns>
public static object Create(Type targetType, IInterceptor interceptor, object[] serviceParameter = null)
{
object proxy = GetProxy(targetType);
((DynamicProxy)proxy).CreateInstance(interceptor);
((DynamicProxy)proxy).service = CreateServiceInstance(targetType, serviceParameter);
return proxy;
}
/// <summary>
/// 创建代理,targetType为类,interceptorType继承IInterceptor,serviceParameter为targetType为类构造函数的参数,parameters为interceptorType构造函数参数
/// </summary>
/// <param name="targetType"></param>
/// <param name="interceptorType"></param>
/// <param name="serviceParameter"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static object Create(Type targetType, Type interceptorType, object[] serviceParameter = null, params object[] parameters)
{
object proxy = GetProxy(targetType);
((DynamicProxy)proxy).CreateInstance(interceptorType, parameters);
((DynamicProxy)proxy).service = CreateServiceInstance(targetType, serviceParameter);
return proxy;
}
/// <summary>
/// tIService为接口,tService实现tIService接口,intercer继承IInterceptor,serviceParameter为targetType为类构造函数的参数,parameters为interceptorType构造函数参数
/// </summary>
/// <param name="tIService"></param>
/// <param name="tService"></param>
/// <param name="intercer"></param>
/// <param name="serviceParameter"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static object Create(Type tIService, Type tService, Type intercer, object[] serviceParameter = null, params object[] parameters)
{
var proxy = GetProxy(tIService);
((DynamicProxy)proxy).CreateInstance(intercer, parameters);
((DynamicProxy)proxy).service = CreateServiceInstance(tService, serviceParameter);
return proxy;
}
/// <summary>
/// TTarget为接口,tService实现tIService接口,TInterceptor继承IInterceptor,serviceParameter为targetType为类构造函数的参数,parameters为interceptorType构造函数参数
/// </summary>
/// <typeparam name="TTarget"></typeparam>
/// <typeparam name="TService"></typeparam>
/// <typeparam name="TInterceptor"></typeparam>
/// <param name="serviceParameter"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static TTarget Create<TTarget, TService, TInterceptor>(object[] serviceParameter = null, params object[] parameters) where TInterceptor : IInterceptor where TService : TTarget
{
var proxy = GetProxy(typeof(TTarget));
((DynamicProxy)proxy).CreateInstance(typeof(TInterceptor), parameters);
((DynamicProxy)proxy).service = CreateServiceInstance(typeof(TService), serviceParameter);
return (TTarget)proxy;
}
/// <summary>
/// 创建指定类型对象,servicePara构造函数参数
/// </summary>
/// <param name="type"></param>
/// <param name="servicePara"></param>
/// <returns></returns>
private static object CreateServiceInstance(Type type, params object[] servicePara)
{
return Activator.CreateInstance(type, servicePara);
}
/// <summary>
/// 创建代理,表达式执行泛型方法性能优于MakeGenericMethod
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
private static object GetProxy(Type targetType)
{
var callexp = Expression.Call(typeof(DispatchProxy), nameof(DispatchProxy.Create), new[] { targetType, typeof(DynamicProxy) });
return Expression.Lambda<Func<object>>(callexp).Compile().Invoke();
}
/// <summary>
/// 创建Aop具体实现类,表达式性能优于反射性能
/// </summary>
/// <param name="interceptorType"></param>
/// <param name="parameters"></param>
private void CreateInstance(Type interceptorType, object[] parameters)
{
var ctorParams = parameters.Select(x => x.GetType()).ToArray();
var paramsExp = parameters.Select(x => Expression.Constant(x));
var newExp = Expression.New(interceptorType.GetConstructor(ctorParams), paramsExp);
this.interceptor = Expression.Lambda<Func<IInterceptor>>(newExp).Compile()();
}
/// <summary>
/// 赋值
/// </summary>
/// <param name="interceptor"></param>
private void CreateInstance(IInterceptor interceptor)
{
this.interceptor = interceptor;
}
/// <summary>
/// 实现Invole方法
/// </summary>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
protected override object Invoke(MethodInfo method, object[] parameters)
{
if (method == null) throw new Exception("无效的方法");
try
{
if (this.interceptor != null)
{
this.interceptor.BeforeEvent(method, parameters);
}
object result = method.Invoke(service, parameters);
if (method.ReturnType.BaseType == typeof(Task))
{
var resultTask = result as Task;
if (resultTask != null)
{
resultTask.ContinueWith(task =>
{
if (task.Exception != null)
{
if (interceptor != null)
{
var resultEx = this.interceptor.ExceptionEvent(task.Exception.InnerException ?? task.Exception, method);
result = resultEx;
}
}
else
{
object taskResult = task.GetType().GetProperty("Result").GetValue(task);
if (interceptor != null)
{
this.interceptor.AfterEvent(method, taskResult);
}
}
}).ConfigureAwait(false).GetAwaiter().GetResult();
return result;
}
}
else
{
try
{
if (interceptor != null)
{
this.interceptor.AfterEvent(method, result);
return result;
}
}
catch (Exception ex)
{
if (interceptor != null)
{
return this.interceptor.ExceptionEvent(ex, method);
}
else
{
return null;
}
}
}
return null;
}
catch (Exception ex)
{
if (interceptor != null)
{
return this.interceptor.ExceptionEvent(ex, method);
}
else
{
return null;
}
}
}
}

从Invoke方法来看,直接成了我们所需要调用的方法的信息,以及对应的参数,那同样的,这个类实际上也有一些缺陷就是,Dispatch这个类里面有一个Create的方法可以去为我们生成代理类,但是这个Create方法,如果你传入的Type是具体的class,Create方法是会报错的,因为Create方法不支持具体的类型,而是对应的父类接口类型,至于抽象类,我没试过,有兴趣的小伙伴可以在后面自己试一下调用Create方法传入的是抽象类的前提下是否可以代理成功。

同样的,在RealProxy中我们可以记录日志,异常,执行前,执行后等操作,在这个Invoke里面,我们同样可以,这便是我在FrameWork以及Core中实现Aop的两种方式。

IL的形式去实现

之前的博客中,我有写过IL方面的合集,那实际上通过使用IL我们也可以实现一个动态代理去实现AOP的功能,目前的话,我是没有写相关的代码,但是IL的话 大体思路是这样的,我们去动态创建DLL以及Module,以及去创建一个Type继承我们需要代理的类或者接口,然后我们需要去用IL去实现父类的那几个方法,然后我们讲我们创建的类型去返回给依赖方,依赖方在调用方法的时候,会进入到我们用IL写的代码中去,在IL构造的方法中,我们可以直接return代理对象的同名同类型的方法,从而实现AOP的功能,可能在这里说的比较抽象,后面我会写一篇使用IL去实现AOP的功能代码,到时候会在博客中一一讲解。

内存的形式

实际上,内存的形式目前我是没有写过,但是在网上有看到过相关的代码,其是利用反射我们获取到方法的MethodHandle然后通过内存的形式,然后通过内存Copy实现的AOP,相关代码目前我已找不到,因为这种方式需要的功力深厚,目前我是达不到的,如果后续研究明白,再来一一分析,分享给大家,下一篇博客的话,我可能会写一些c#中跨进程通讯的各种手段。

RealProxy版本:http://121.43.235.192:8082/s/Sb5xs7rH88CECn6

DispatchProxy版本:http://121.43.235.192:8082/s/xpKFAWc6rpb7nd6

DispatchProxy版本中,我是实现了一个EFCore的一个读写分离,实现了读写分离的两种方式的一个案例。

大家如果有不懂的地方,可以看如果自己加的net群里有叫四川观察的基本上就是我,或者可以直接添加群聊可以找到我,在此,谢谢各位大佬的支持,后续依旧会带来更多的干货

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,105
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,582
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,429
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,836
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,919