浅析DispatchProxy动态代理AOP(代码源码)
最近学习了一段时间Java,了解到Java实现动态代理
AOP
主要分为两种方式JDK
、CGLIB
,我之前使用NET
实现AOP
切面编程,会用Filter拦截器
、Attribute特性
、中间件
、继承父类重写父类方法
。
经过查找资料接触到了(牛逼不分先后)
DispatchProxy类介绍
DispatchProxy源码,主要使用了Emit
类库直接编写IL
语言,动态生成类,和方法,然后会调用Invoke
方法(性能很高,几乎和我们写的C#编译成IL没有区别),我们继承了DispatchProxy
抽象类,重写Invoke
方法,具体实现就可以自定义了。
DispatchProxy源码
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
我们会有很多处理实现类,每个实现类都需要实现AfterAction
、BeforeAction
、TargetMethodExceptionAction
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}"); } }
- 准备
ITestService
、TestService
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切面编程原理差不多。