浅析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. Python的组合数据类型

    """ Python的组合类型: 序列类型:元素之间存在先后关系,可以通过索引来访问 列表: 元组: 字符串: 映射类型:用键值来表示数据 字典: 集合类型:元素是无序的 ...

  2. Python入门-面向对象-装饰器

    1.变量作用域 全局变量和局部变量 #变量是有作用域的,分为全局变量和局部变量 num = 100 #这是全局变量 def change(): """ 查看变量作用域 & ...

  3. LC-76

    给你一个字符串 s .一个字符串 t .返回 s 中涵盖 t 所有字符的最小子串.如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" . 注意: 对于 t 中重复字符 ...

  4. 安全市场迎来新挑战,FinClip助力车联网数据安全

    随着汽车工业的发展与电子技术的进步,智能汽车迎来了前所未有的蓬勃发展,随着汽车电动化.网联化.智能化交融发展,车辆运行安全.数据安全和网络安全风险交织叠加,安全形势更加复杂严峻......

  5. Java学习day15

    File是文件和目录路径名的抽象表示 文件和目录可以通过File封装成对象 对于File而言,封装的不是一个真正存在的文件,只是一个路径名,它可以存在,也可以不存在,要通过后续操作把路径的内容转换为具 ...

  6. mysql组提交

    当mysql开启binlog日志时,会存在一个内部XA的问题:事务在存储引擎层redo log的写入和binlog的写入一致性问题. mysql通过两阶段提交很好的解决了redo log和binlog ...

  7. 2021.07.19 BZOJ2654 tree(生成树)

    2021.07.19 BZOJ2654 tree(生成树) tree - 黑暗爆炸 2654 - Virtual Judge (vjudge.net) 重点: 1.生成树的本质 2.二分 题意: 有一 ...

  8. client 系列

    定义 : client翻译过来就是客户端,我们使用client系列的相关属性来获取元素可视区的相关信息.通过client系列的相关属性可以动态的得到该元素的边框大小.元素大小等.

  9. 【面试普通人VS高手系列】b树和b+树的理解

    数据结构与算法问题,困扰了无数的小伙伴. 很多小伙伴对数据结构与算法的认知有一个误区,认为工作中没有用到,为什么面试要问,问了能解决实际问题? 图灵奖获得者: Niklaus Wirth 说过: 程序 ...

  10. ValidForm5.3.2 忽略表单项校验详解

    ValidForm 官方文档 项目的需求是这样的:一个checkbox,一个input,选中checkbox的时候,需要校验input,取消选中的时候,不要校验input. <input typ ...