Net 实现自定义Aop
引言
何为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群里有叫四川观察的基本上就是我,或者可以直接添加群聊可以找到我,在此,谢谢各位大佬的支持,后续依旧会带来更多的干货
Net 实现自定义Aop的更多相关文章
- .net 自定义AOP,透明代理与真实代理
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.R ...
- 自定义ThreadLocal和事务(基于自定义AOP)
参考<架构探险--从零开始写javaweb框架>4.6章节 自定义ThreadLocal package smart; import java.util.Collections; impo ...
- spring boot+自定义 AOP 实现全局校验
最近公司重构项目,重构为最热的微服务框架 spring boot, 重构的时候遇到几个可以统一处理的问题,也是项目中经常遇到,列如:统一校验参数,统一捕获异常... 仅凭代码 去控制参数的校验,有时候 ...
- Android自定义Aop的Gradle Plugin
[上一篇文章]中讲解了如何在Android使用AOP,会发现在Gradle配置aop会比较麻烦,每个module使用了aop都需要配置.接下来看如何简化配置. 1.创建Module 首先,需要建立一个 ...
- 像@Transactional一样利用注解自定义aop切片
在spring中,利用@Transactional注解可以很轻松的利用aop技术进行事物管理.在实际项目中,直接利用自定义注解实现切片可以大大的提高我们的编码效率以及代码的简洁性. 实现以上的目标,主 ...
- [SpringMVC+redis]自定义aop注解实现控制器访问次数限制
原文:http://www.cnblogs.com/xiaoyangjia/p/3762150.html?utm_source=tuicool 我们需要根据IP去限制用户单位时间的访问次数,防止刷手机 ...
- 基于DispatchProxy打造自定义AOP组件
DispatchProxy是微软爸爸编写的一个代理类,基于这个,我扩展了一个AOP组件 暂时不支持依赖注入构造方法,感觉属性注入略显麻烦,暂时没打算支持 基于特性的注入流程 [AttributeUsa ...
- spring自定义aop
package com.dhht.config.articleAdvice; import com.dhht.util.UUIDUtil;import lombok.extern.slf4j.Slf4 ...
- 利用Spring AOP自定义注解解决日志和签名校验
转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...
随机推荐
- Spring Boot,Spring Cloud,Spring Cloud Alibaba 版本选择说明以及整理归纳
前言 本文的核心目的: 1.方便自己以后的查找,预览,参考 2.帮助那些不知道如何选择版本的朋友进行指引,而不是一味的跟风网上的版本,照抄. Spring Boot 版本 版本查询: https:// ...
- Hibernate的基本功能:对数据库的增删改查(创建对象实例)
一.通过实例化的对象向数据库添加新记录 package com.yh.test; import org.hibernate.Session; import org.hibernate.SessionF ...
- MVC+Servlet+mysql+jsp读取数据库信息
首先有以下几个包: 1.controller 控制层,对用户的请求进行响应 2.dao 数据层接口标准 3.daoimpl 数据层实现层 4.model 实体类层 5.service 业务层接口标准 ...
- gitlab 备份&恢复
Gitlab 成功运行起来之后,最终的事情就是定期的备份,遇到问题后的还原. 备份配置 默认 Gitlab 的备份文件会创建在/var/opt/gitlab/backups文件夹中,格式为时间戳_日期 ...
- useEffect无限调用问题
1.useEfect()的基本用法 const [test,setTest] = useState(1) const init=()=>{ setTest(2) } useEffect(()=& ...
- ciscn_2019_s_6
例行检查 没有开启nx保护,考虑用shellcode来做这道题 程序放入ida查看 我们可以输入48个字符覆盖0使printf打印出bp的值 继续看这里,buf的大小实际上只有0x38的大小,但是re ...
- *CTF pwn write up
第一次做出XCTF的题目来,感谢wjh师傅的指点,虽然只做出一道最简单的pwn题,但是还是挺开心的.此贴用来记录一下,赛后试着看看其他大师傅的wp,看看能不能再做出一道题来. babyheap 程序有 ...
- Element-UI 使用 class 方式和 css 方式引入图标
今天在使用 vxe-table 时,需要引入 Element UI的图标,顺便就找了下这些组件库中图标的引用方式. 我们知道 Element .Ant Design.Font Awesome 等很多组 ...
- Tornadofx学习笔记(4)——IconTextFx开源库,整合5000+个字体图标
JavaFx中其实也可以直接使用字体图标iconfont的,只需要加载ttf字体文件,之后设置unicode即可,具体可以看我给出的代码 既然JavaFx可以,那么以JavaFx为基础的Tornado ...
- LuoguB2103 图像相似度 题解
Content 给定两个 \(m\times n\) 的矩阵 \(A,B\),求 \(A,B\) 两个矩阵的相似度,精确到小数点后 \(2\) 位. 定义两个矩阵的相似度为两个矩阵对应相同元素个数占矩 ...