浅析DispatchProxy动态代理AOP(代码源码)

最近学习了一段时间Java,了解到Java实现动态代理AOP主要分为两种方式JDKCGLIB,我之前使用NET实现AOP切面编程,会用Filter拦截器Attribute特性中间件继承父类重写父类方法

经过查找资料接触到了(牛逼不分先后)

DispatchProxy类介绍

DispatchProxy源码,主要使用了Emit类库直接编写IL语言,动态生成类,和方法,然后会调用Invoke方法(性能很高,几乎和我们写的C#编译成IL没有区别),我们继承了DispatchProxy抽象类,重写Invoke方法,具体实现就可以自定义了。

DispatchProxy源码

DispatchProxy主要是Activator(文档地址)以及AssemblyBuilder(文档地址)实现,

  • Activator 类在运行时可以动态构造对象
  • AssemblyBuilder 类在运行时可以动态获取和设置专用字段的属性、初始化专用字段的构造函数,动态执行方法并返回结果。

    // 动态代理生成类
internal static class DispatchProxyGenerator
{
// 动态代理容器(保存已经生成过的代理)
private static readonly Dictionary<Type, Dictionary<Type, Type>> s_baseTypeAndInterfaceToGeneratedProxyType = new Dictionary<Type, Dictionary<Type, Type>>();
private static readonly ProxyAssembly s_proxyAssembly = new ProxyAssembly();
private static readonly MethodInfo s_dispatchProxyInvokeMethod = typeof(DispatchProxy).GetTypeInfo().GetDeclaredMethod("Invoke"); // 返回派生自'baseType'的代理的新实例,并实现'interfaceType'
internal static object CreateProxyInstance(Type baseType, Type interfaceType)
{
Debug.Assert(baseType != null);
Debug.Assert(interfaceType != null);
// 获取代理类型
Type proxiedType = GetProxyType(baseType, interfaceType);
// 创建实例
return Activator.CreateInstance(proxiedType, (Action<object[]>)DispatchProxyGenerator.Invoke);
} // 首先从代理容器中获取,如果没有进行创建
private static Type GetProxyType(Type baseType, Type interfaceType)
{
// 锁住容器
lock (s_baseTypeAndInterfaceToGeneratedProxyType)
{
Dictionary<Type, Type> interfaceToProxy = null;
// 判断baseType实现类类型容器中是否存在,不存在先初始化一个
if (!s_baseTypeAndInterfaceToGeneratedProxyType.TryGetValue(baseType, out interfaceToProxy))
{
interfaceToProxy = new Dictionary<Type, Type>();
s_baseTypeAndInterfaceToGeneratedProxyType[baseType] = interfaceToProxy;
}
Type generatedProxy = null;
// 判断是否存在interfaceType接口类型代理类,不存在就创建一个
if (!interfaceToProxy.TryGetValue(interfaceType, out generatedProxy))
{
generatedProxy = GenerateProxyType(baseType, interfaceType);
interfaceToProxy[interfaceType] = generatedProxy;
} return generatedProxy;
}
} // 生成一个派生自'baseType'的新代理类型,并实现'interfaceType'
private static Type GenerateProxyType(Type baseType, Type interfaceType)
{
TypeInfo baseTypeInfo = baseType.GetTypeInfo(); // 接口类型必须是接口,而不是类
if (!interfaceType.GetTypeInfo().IsInterface)
{
throw new ArgumentException(SR.Format(SR.InterfaceType_Must_Be_Interface, interfaceType.FullName), "T");
} // 基类型不能密封,因为代理需要将其子类化。
if (baseTypeInfo.IsSealed)
{
throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Sealed, baseTypeInfo.FullName), "TProxy");
} // 基类型不能是抽象类型
if (baseTypeInfo.IsAbstract)
{
throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Abstract, baseType.FullName), "TProxy");
} // 基类型必须有一个公共默认属性(不然没啥意义)
if (!baseTypeInfo.DeclaredConstructors.Any(c => c.IsPublic && c.GetParameters().Length == 0))
{
throw new ArgumentException(SR.Format(SR.BaseType_Must_Have_Default_Ctor, baseType.FullName), "TProxy");
} // 创建baseType类
ProxyBuilder pb = s_proxyAssembly.CreateProxy("generatedProxy", baseType); // 获取接口中需要实现的信息,动态添加实现
foreach (Type t in interfaceType.GetTypeInfo().ImplementedInterfaces)
pb.AddInterfaceImpl(t); // 添加实现
pb.AddInterfaceImpl(interfaceType); // 实现完接口,创建该类型
Type generatedProxyType = pb.CreateType();
return generatedProxyType;
} // 调用(抽象的)DispatchProxy.Invoke()方法。
private static void Invoke(object[] args)
{
PackedArgs packed = new PackedArgs(args);
MethodBase method = s_proxyAssembly.ResolveMethodToken(packed.DeclaringType, packed.MethodToken);
// 方法是否泛型方法定义
if (method.IsGenericMethodDefinition)
// 创建泛型方法定义
method = ((MethodInfo)method).MakeGenericMethod(packed.GenericTypes); // 调用(抽象的)DispatchProxy.Invoke()方法
try
{
Debug.Assert(s_dispatchProxyInvokeMethod != null);
// 执行packed.DispatchProxy该类方法,获取方法的返回结果
object returnValue = s_dispatchProxyInvokeMethod.Invoke(packed.DispatchProxy,
new object[] { method, packed.Args });
// 执行返回结果
packed.ReturnValue = returnValue;
}
catch (TargetInvocationException tie)
{
ExceptionDispatchInfo.Capture(tie.InnerException).Throw();
}
}

DispatchProxy拓展封装

根据前面的介绍,对DispatchProxy有了一定的了解,我们可以进行一些封装方便以后使用。

DynamicProxy动态代理类

我们创建DynamicProxy类,包装方法执行之前&执行之后的处理,主体方法报错的处理,形成一个动态代理类。

    public class DynamicProxy : DispatchProxy, IScopedDependency
{
private static ILogger<DynamicProxy>? _logger { get; set; } /// <summary>
/// 目标类
/// </summary>
public object Target { get; set; } /// <summary>
/// 动作之后执行
/// </summary>
private Action<object?[]?> _afterAction { get; set; } /// <summary>
/// 动作之前执行
/// </summary>
private Action<object?[]?, object> _beforeAction { get; set; } /// <summary>
/// 目标方法异常(默认抛出异常信息)
/// </summary>
private Action<MethodInfo?, object?[]?, Exception> _methodExceptionAction { get; set; } = (methodInfo, args, ex) => throw ex; /// <summary>
/// 执行方法
/// </summary>
/// <param name="targetMethod">目标方法</param>
/// <param name="args">方法参数</param>
/// <returns></returns>
protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
// 异常信息
Exception exception = null;
// 方法执行前处理
AfterAction(args);
// 方法执行结果
object resultValue = null;
if (targetMethod != null)
{
try
{
//调用实际目标对象的方法
resultValue = targetMethod.Invoke(Target, args);
}
catch (Exception ex)
{
_logger.LogError($"Invoke=>调用实际目标对象的方法出现错误:{ex.Message},{ex.StackTrace}");
_methodExceptionAction(targetMethod, args, ex);
}
}
// 方法执行后处理
BeforeAction(args, resultValue); // 判断主体方法执行是否异常
if (exception != null)
{
throw exception;
} return resultValue;
} /// <summary>
/// 创建代理实例
/// </summary>
/// <param name="target">代理的接口类型</param>
/// <param name="afterAction">方法执行前执行的事件</param>
/// <param name="beforeAction">方法执行后执行的事件</param>
/// <returns></returns>
public T Create<T>(T target,
Action<object?[]?> afterAction,
Action<object?[]?, object> beforeAction,
Action<MethodInfo?, object?[]?, Exception> targetMethodExceptionAction,
ILogger<DynamicProxy> logger)
{
// DispatchProxy.Create创建T对象
object proxy = Create<T, DynamicProxy>();
_logger = logger;
DynamicProxy proxyDecorator = (DynamicProxy)proxy;
proxyDecorator.Target = target;
proxyDecorator._afterAction = afterAction;
proxyDecorator._beforeAction = beforeAction;
proxyDecorator._methodExceptionAction = targetMethodExceptionAction;
return (T)proxy;
} private void AfterAction(object?[]? args)
{
if (_afterAction == null)
{
return;
} try
{
_afterAction.Invoke(args);
}
catch (Exception ex)
{
_logger.LogError($"AfterAction=>执行之前异常:{ex.Message},{ex.StackTrace}");
}
} private void BeforeAction(object?[]? args, object? result)
{
if (_beforeAction == null)
{
return;
} try
{
_beforeAction.Invoke(args, result);
}
catch (Exception ex)
{
_logger.LogError($"BeforeAction=>执行之后异常:{ex.Message},{ex.StackTrace}");
}
}
}

创建IProxyHandle

我们会有很多处理实现类,每个实现类都需要实现AfterActionBeforeActionTargetMethodExceptionAction

   public interface IProxyHandle
{
/// <summary>
/// 执行之前
/// </summary>
/// <param name="args">目标方法参数</param>
void AfterAction(object?[]? args); /// <summary>
/// 执行之后
/// </summary>
/// <param name="args">目标方法参数</param>
/// <param name="result">目标方法执行结果</param>
void BeforeAction(object?[]? args, object resultValue); /// <summary>
/// 方法执行错误处理
/// </summary>
/// <param name="targetMethod">目标方法</param>
/// <param name="args">目标方法参数</param>
/// <param name="ex">目标方法执行结果</param>
void MethodExceptionAction(MethodInfo? targetMethod, object?[]? args, Exception ex);
}

创建ProxyHandleAttribute特性

这里我尝试过几种方式,通过接口或者使用特性,最终特性比较方便团队使用(接口也不错)。

    /// <summary>
/// 代理Aop特性
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ProxyHandleAttribute : Attribute
{
public Type Type { get; set; }
public ProxyHandleAttribute(Type type)
{
this.Type = type;
}
}

ProxyFactory代理工厂

根据实现类获取Aop切面类型,再获取AOP工厂(IEnumerable<IProxyHandle>)中对应实现。

    /// <summary>
/// 代理工厂
/// </summary>
public class ProxyFactory : IScopedDependency
{
private readonly IServiceProvider _serviceProvider;
private readonly IEnumerable<IProxyHandle> _proxyHandleList;
private readonly DynamicProxy _dynamicProxy;
private readonly ILogger<DynamicProxy> _logger;
public ProxyFactory(IEnumerable<IProxyHandle> proxyHandleList,
IServiceProvider serviceProvider,
DynamicProxy dynamicProxy,
ILogger<DynamicProxy> logger)
{
this._serviceProvider = serviceProvider;
this._proxyHandleList = proxyHandleList;
this._dynamicProxy = dynamicProxy;
this._logger = logger;
} /// <summary>
/// 创建代理实例
/// </summary>
/// <returns></returns>
public T Create<T>() where T : class
{ var target = _serviceProvider.GetService<T>();
if (target == null)
{
throw new BusinessException($"执行ProxyFactory=》Create方法:{typeof(T).FullName}未注入");
}
var type = target.GetType();
var proxyHandleAttribute = type.GetCustomAttribute<ProxyHandleAttribute>();
if (proxyHandleAttribute == null)
{
throw new BusinessException($"执行ProxyFactory=》Create方法:{type.FullName}需要添加ProxyHandleAttribute特性");
}
var proxyHandle = _proxyHandleList.FirstOrDefault(x => x.GetType() == proxyHandleAttribute.Type);
if (proxyHandleAttribute == null)
{
throw new BusinessException($"执行ProxyFactory=》Create方法:没有找到对应IProxyHandle接口实现");
}
//创建代理类
var proxy = _dynamicProxy.Create(target,
proxyHandle.AfterAction,
proxyHandle.BeforeAction,
proxyHandle.MethodExceptionAction,
_logger);
return proxy;
}
}

DynamicProxy使用示例

  • IProxyHandle实现类(ProxyHandleTest)
public class ProxyHandleTest : IProxyHandle
{
public void AfterAction(object[] args)
{
Console.WriteLine($"ProxyHandleTest=》AfterAction方法执行,args:{JsonSerializer.Serialize(args)}");
} public void BeforeAction(object[] args, object resultValue)
{
Console.WriteLine($"ProxyHandleTest=》BeforeAction方法执行,args:{JsonSerializer.Serialize(args)},result:{resultValue}");
} public void MethodExceptionAction(MethodInfo targetMethod, object[] args, Exception ex)
{
Console.WriteLine($"ProxyHandleTest=》MethodExceptionAction方法执行,targetMethod,:{targetMethod.Name},args:{JsonSerializer.Serialize(args)},ex:{ex.Message}");
}
}
  • 准备ITestServiceTestService
public interface ITestService
{
/// <summary>
/// 获取用户Id信息
/// </summary>
/// <returns></returns>
int GetUserId(); void SetUserId(int userId);
} [ProxyHandle(typeof(ProxyHandleTest))]
public class TestService : ITestService, IScopedDependency
{
public int GetUserId()
{
Console.WriteLine($"执行TestService=>GetUserId()");
return 10;
} public void SetUserId(int userId)
{
Console.WriteLine($"执行TestService=>SetUserId({userId})");
throw new Exception("执行TestService=>SetUserId测试异常");
}
}
  • 最后只需要注入ProxyFactory
    public class TestController : AbpController
{
private readonly ProxyFactory _proxyFactory;
public TestController(ProxyFactory proxyFactory)
{
_proxyFactory = proxyFactory;
} // GET: api/<TestController>
[HttpGet]
public IEnumerable<string> Get()
{
// 从工厂获取代理类
var testService = _proxyFactory.Create<ITestService>();
testService.GetUserId();
return new string[] { "value1", "value2" };
}

总结

  • DispatchProxy 实现动态代理主要是依赖Emit类库直接编写IL语言。
  • Activator 类在运行时动态构造对象。
  • AssemblyBuilder 类运行时动态一个获取和设置专用字段的属性、初始化专用字段的构造函数,可以动态执行方法并返回结果。

不管是Java还是Net实现AOP切面编程原理差不多。

浅析DispatchProxy动态代理AOP的更多相关文章

  1. 动态代理AOP实现方法过滤

    上一节实现了动态代理,接下来 有时候,我不需要在每一个方法都要记录日志,做权限验证 等等. 所有就有了这样的需求.AOP实现特定方法过滤,有选择性的来对方法实现AOP 拦截.就是本节标题所示. 举个例 ...

  2. 动态代理 aop切面实现事务管理

    1.定义接口和实现 public interface UserService { public String getName(int id); public Integer getAge(int id ...

  3. Spring-Boot的动态代理AOP原理

    前言 Spring AOP使用了动态代理技术,动态代理在业界比较流行的实现方式有,CGLIB,Javassist,ASM等等. Spring动态代理实现方式 Spring采用了JDK和CGLIB两种方 ...

  4. 5.动态代理AOP实现-DynamicProxy模式

    通过动态代理模式Interceptor实现在RegUser()方法本身业务前后加上一些自己的功能,如:PreProceed和PostProceed,即不修改UserProcessor类又能增加新功能 ...

  5. spring中使用动态代理(AOP)

    spring是整合了BGLIB和JDK两种动态代理 示例:使用CGLIB代理 public class MyCar { private String color = "blue"; ...

  6. Cglib动态代理浅析

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2018-06-29/18.html 作者:夜月归途 出处:http://www.guitu ...

  7. JDK动态代理浅析

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2018-06-29/17.html 作者:夜月归途 出处:http://www.guitu ...

  8. [编织消息框架][JAVA核心技术]cglib动态代理

    先在mavne项目里添加cglib库 maven仓库搜索cglib版本 maven地址:http://mvnrepository.com/ 点击最新的版本 3.2.5 复制到pom.xml  depe ...

  9. JDK动态代理深入理解分析并手写简易JDK动态代理(下)

    原文同步发表至个人博客[夜月归途] 原文链接:http://www.guitu18.com/se/java/2019-01-05/27.html 作者:夜月归途 出处:http://www.guitu ...

随机推荐

  1. Java多线程与线程池技术

    一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...

  2. linux磁盘之分区类型id

    我们通过命令来查看一下linux系统定义的分区类型id及其意义(更改磁盘分区类型必须掌握)系统采样: [root@fp-web-130 ~]# cat /etc/redhat-release Cent ...

  3. C++ functional库中的仿函数

    一.仿函数简介 仿函数(functor)又称之为函数对象(function object),实际上就是 重载了()操作符 的 struct或class. 由于重载了()操作符,所以使用他的时候就像在调 ...

  4. 在线操作word和在线预览查找的资料记录

    在线操作word和在线预览查找的资料记录 在线操作word查找的资料记录 富文本操作 http://fex.baidu.com/ueditor/ 控件类 通过 js 调用控件操作 word 文档 1. ...

  5. mongodb replication

    官方文档:https://docs.mongodb.com/manual/replication/ 启动参数: 通过linux的包管理器(例如:yum)安装的mongodb会产生一个默认的配置文件:/ ...

  6. 腾讯云OCR服务二次开发

    本文记录了对腾讯云OCR服务二次开发的代码和开发过程中遇到的问题.

  7. 安全开发运维必备,如何进行Nginx代理Web服务器性能优化与安全加固配置,看这篇指南就够了

    本章目录 1.引言 1.1 目的 1.2 目标范围 1.3 读者对象 2.参考说明 2.1 帮助参考 2.2 参数说明 3.3 模块说明 3.服务优化 3.1 系统内核 3.2 编译优化 3.3 性能 ...

  8. 2021.11.14 CF1583E Moment of Bloom(LCA+图上构造)

    2021.11.14 CF1583E Moment of Bloom(LCA+图上构造) https://www.luogu.com.cn/problem/CF1583E 题意: She does h ...

  9. Windows资源管理器文件名排序

    Windows资源管理器文件名排序 Windows资源管理器文件名排序 背景:自然排序 什么是自然排序? 怎样按自然排序的规则进行排序? 基于Python的解决方案 参考材料 这学期担任了本科生教学助 ...

  10. 记录Neo4j上写的简单cypher语法

    neo4j是一个高性能的图形数据库,既然是数据库,那么主要操作就是增.删.改.查.所以进入正题: 一.CREATE:创建 语法如下: 1.create(变量名:标签名) :建立一个标签为Animal的 ...