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首先 ...
随机推荐
- java标识接口
标识接口是没有任何方法和属性的接口,标识接口不对实现类有任何语义上的要求,仅仅表明它的实现类属于一个特定的类型.它非常类似于Web 2.0中的TAG的概念,Java使用它标识某一类对象.主要有两个用途 ...
- SpringMVC(2):JSON
一,JSON 介绍 JSON (JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效 ...
- 【Linux】【Shell】【Basic】文件查找locate,find
1.locate: 1.1. 简介:依赖于事先构建好的索引库: 系统自动实现(周期性任务): 手动更新数据库(updatedb): 1.2. 工作特性:查找速度快:模糊 ...
- spring boot springMVC扩展配置 。WebMvcConfigurer ,WebMvcConfigurerAdapter
摘要: 在spring boot中 MVC这部分也有默认自动配置,也就是说我们不用做任何配置,那么也是OK的,这个配置类就是 WebMvcAutoConfiguration,但是也时候我们想设置自己的 ...
- QPS和TPS的区别于理解
TPS: (每秒事务处理量(TransactionPerSecond)) 一个表达系统处理能力的性能指标,每秒处理的消息数(Transaction Per Second),每秒事务处理量 - 性能测试 ...
- Mybatis环境搭建及测试
1.新建java project,导入相应jar包 本次使用到的mybatis-3.2.7版本 mybatis需要jar包:mybatis-3.2.7.jar.lib文件下的依赖jar mysql驱动 ...
- 解决用creact-react-app新建React项目不支持 mobx装饰器模式导致报错问题 。
创建react项目 create-react-app mobx-demo cd my-app npm run start 使用react-app-rewired npm install customi ...
- Python解释器下载安装
一.简介 吉多·范罗苏姆(Guido van Rossum)在1989年的圣诞节期间,编写能够解释Python语言语法的解释器. 解释器版本 第一个数字是大版本号 数字不同功能上可能会有很大差异 py ...
- Python的 垃圾回收机制
垃圾回收 1. 小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间. Python 对小整数的定义是 [-5, 257) 这些整 ...
- JAVA字符串去掉html代码,获取内容
有时候我们需要在html代码中获取到文本内容,需要把html代码中的标签过滤掉 String htmlStr="html代码"; htmlStr = htmlStr.replace ...