翼度科技»论坛 编程开发 .net 查看内容

.net core IOC 容器实现(四) -- CallSiteRuntimeResolver

10

主题

10

帖子

30

积分

新手上路

Rank: 1

积分
30
上一节聊了一下 CallSite 是怎样生成的,这一节我们来看一下 CallSite 是如何使用的。
入口

先让我们来回顾一下  CreateServiceAccessor 这个方法。
  1. private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType)        
  2. {
  3.     //通过 服务类型 获取 callSite           
  4.     ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());            
  5.     if (callSite != null)           
  6.     {                           
  7.         if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)               
  8.         {               
  9.             //直接解析   
  10.             object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);                                 
  11.         }                       
  12.         return _engine.RealizeService(callSite);            
  13.     }
  14. }
复制代码
这段代码跟 CallSite 有关的一共有三个地方,分别是 GetCallSite 和 Resolve(callSite,Root)以及 _engine.RealizeService。其中 GetCallSite 是用来生成 CallSite 的(也就是上一节的主要内容),而剩下的两个则是对于 CallSite 的使用,也是这一节的主要内容。
RealizeService

我们先看一下 _engine.RealizeService 方法。
  1. public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
  2. {                     
  3.     return scope =>            
  4.     {               
  5.         var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);                       
  6.         return result;            
  7.     };        
  8. }
复制代码
我们可以发现最终调用的还是 CallSiteRuntimeResolver.Instance.Resolve 这个方法,所以其实归根结底对 CallSite 的调用其实最终就是一个地方,也就是这个 Resolve 方法。
CallSiteRuntimeResolver.Resolve
  1. public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
  2. {
  3.     // 如果在 root scope 范围里已经有缓存了,直接返回
  4.     if (scope.IsRootScope && callSite.Value is object cached)
  5.     {
  6.         return cached;
  7.     }
  8.     //调用 VisitCallSite 进行解析
  9.     return VisitCallSite(callSite, new RuntimeResolverContext
  10.     {
  11.         Scope = scope
  12.     });
  13. }
复制代码
VisitCallSite
  1. protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
  2. {
  3.     switch (callSite.Cache.Location)
  4.     {
  5.         case CallSiteResultCacheLocation.Root:
  6.             return VisitRootCache(callSite, argument);
  7.         case CallSiteResultCacheLocation.Scope:
  8.             return VisitScopeCache(callSite, argument);
  9.         case CallSiteResultCacheLocation.Dispose:
  10.             return VisitDisposeCache(callSite, argument);
  11.         case CallSiteResultCacheLocation.None:
  12.             return VisitNoCache(callSite, argument);
  13.         default:
  14.             throw new ArgumentOutOfRangeException();
  15.     }
  16. }
复制代码
VisitCallSite 会根据 Location 进行分支处理,Location 是 CallSite 里的一个属性。其中 Root 对应 Singleton,Scope 对应 Scope 生命周期,Dispose 对应 Trasient,None可以先将其理解为Singleton。
VisitRootCache(Single)
  1. protected override object? VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
  2. {
  3.     // Singleton 懒加载 如果有 value 直接返回         
  4.     if (callSite.Value is object value)
  5.     {
  6.         // Value already calculated, return it directly
  7.         return value;
  8.     }
  9.     var lockType = RuntimeResolverLock.Root;
  10.     //在 root 范围进行解析
  11.     ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
  12.     // 锁住 callSite 防止重复生成value
  13.     lock (callSite)
  14.     {
  15.         // Lock the callsite and check if another thread already cached the value
  16.         // 可能其他地方已经生成了,在获取一下看看        
  17.         if (callSite.Value is object callSiteValue)
  18.         {
  19.             return callSiteValue;
  20.         }
  21.         //最终依旧是调用了 VisitCallSiteMain 方法
  22.         object? resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
  23.         {
  24.             Scope = serviceProviderEngine,
  25.             AcquiredLocks = context.AcquiredLocks | lockType
  26.         });
  27.         serviceProviderEngine.CaptureDisposable(resolved);
  28.         //进行缓存
  29.         callSite.Value = resolved;
  30.         return resolved;
  31.     }
  32. }
复制代码
VisitScopeCache(Scope)
  1. // Check if we are in the situation where scoped service was promoted to singleton
  2. // and we need to lock the root
  3. // Scope 依赖 Singleton
  4. return context.Scope.IsRootScope ?
  5.     VisitRootCache(callSite, context) :
  6.     VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
复制代码
  1. private object? VisitCache(
  2.     ServiceCallSite callSite,
  3.     RuntimeResolverContext context,
  4.     ServiceProviderEngineScope serviceProviderEngine,
  5.     RuntimeResolverLock lockType)
  6. {
  7.     bool lockTaken = false;
  8.     object sync = serviceProviderEngine.Sync;
  9.     // Dictionary<ServiceCacheKey, object?> ResolvedServices { get; } 缓存
  10.     Dictionary<ServiceCacheKey, object?> resolvedServices = serviceProviderEngine.ResolvedServices;
  11.     // Taking locks only once allows us to fork resolution process
  12.     // on another thread without causing the deadlock because we
  13.     // always know that we are going to wait the other thread to finish before
  14.     // releasing the lock
  15.     // 锁住 sync 对象
  16.     if ((context.AcquiredLocks & lockType) == 0)
  17.     {
  18.         Monitor.Enter(sync, ref lockTaken);
  19.     }
  20.     try
  21.     {
  22.         //获取锁之后
  23.         // Note: This method has already taken lock by the caller for resolution and access synchronization.
  24.         // For scoped: takes a dictionary as both a resolution lock and a dictionary access lock.
  25.         //先访问缓存
  26.         if (resolvedServices.TryGetValue(callSite.Cache.Key, out object? resolved))
  27.         {
  28.             return resolved;
  29.         }
  30.         //解析
  31.         resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
  32.         {
  33.             Scope = serviceProviderEngine,
  34.             AcquiredLocks = context.AcquiredLocks | lockType
  35.         });
  36.         //缓存需要释放的实例
  37.         serviceProviderEngine.CaptureDisposable(resolved);
  38.         //放入缓存
  39.         resolvedServices.Add(callSite.Cache.Key, resolved);
  40.         return resolved;
  41.     }
  42.     finally
  43.     {
  44.         //解锁
  45.         if (lockTaken)
  46.         {
  47.             Monitor.Exit(sync);
  48.         }
  49.     }
  50. }
复制代码
VisitDisposeCache(Transient)
  1. protected override object? VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)        
  2. {   
  3.     //解析        
  4.     var instance=VisitCallSiteMain(transientCallSite, context);
  5.     return context.Scope.CaptureDisposable(instance);        
  6. }
复制代码
VisitNoCache(None)
  1. protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
  2. {
  3.     return VisitCallSiteMain(callSite, argument);
  4. }
复制代码
VisitCallSiteMain

观察以上方法,我们可以发现无论是 VisitRootCache还是VisitScopeCache 等等,最终都是调用 VisitCallSiteMain 这个方法来生成的实例。
  1. protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
  2. {
  3.     //callSite.kind 是只读属性 ,在 GetCallSite 时确定,根据 CallSite 类型确定(例 ConstantCallSite)
  4.     switch (callSite.Kind)
  5.     {
  6.         case CallSiteKind.Factory:
  7.             return VisitFactory((FactoryCallSite)callSite, argument);
  8.         case CallSiteKind.IEnumerable:
  9.             return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
  10.         case CallSiteKind.Constructor:
  11.             return VisitConstructor((ConstructorCallSite)callSite, argument);
  12.         case CallSiteKind.Constant:
  13.             return VisitConstant((ConstantCallSite)callSite, argument);
  14.         case CallSiteKind.ServiceProvider:
  15.             return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
  16.         default:
  17.             throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
  18.     }
  19. }
复制代码
VisitConstructor

其中比较复杂的就是这个 VisitConstructor 方法,通过反射来构造实例,主要思路是拿到实例类型的构造函数,然后通过递归(调用VisitCallSite(见本文最上方))准备构造函数所需要的参数,最后调用 invoke 来生成实例。
  1. protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
  2. {
  3.     object?[] parameterValues;
  4.     //获取构造需要使用的参数
  5.     //无参
  6.     if (constructorCallSite.ParameterCallSites.Length == 0)
  7.     {
  8.         parameterValues = Array.Empty<object>();
  9.     }
  10.     //有参
  11.     else
  12.     {
  13.         parameterValues = new object?[constructorCallSite.ParameterCallSites.Length];
  14.         for (int index = 0; index < parameterValues.Length; index++)
  15.         {
  16.             //递归解析 VisitCallSite 见上文
  17.             parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
  18.         }
  19.     }
  20. #if NETFRAMEWORK || NETSTANDARD2_0
  21.             try
  22.             {
  23.                 return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
  24.             }
  25.             catch (Exception ex) when (ex.InnerException != null)
  26.             {
  27.                 ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
  28.                 // The above line will always throw, but the compiler requires we throw explicitly.
  29.                 throw;
  30.             }
  31. #else
  32.     return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null,
  33.                                                         parameters: parameterValues, culture: null);
  34. #endif
  35. }
复制代码
VisitFactory
  1. protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
  2. {
  3.     //调用  Factory(Func<IServiceProvider, object> Factory) 委托(委托由开发者实现)
  4.     return factoryCallSite.Factory(context.Scope);
  5. }
复制代码
VisitIEnumerable
  1. protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
  2. {
  3.     //创建枚举类型的数组
  4.     var array = Array.CreateInstance(
  5.         enumerableCallSite.ItemType,
  6.         enumerableCallSite.ServiceCallSites.Length);                           
  7.     //给数组填充值
  8.     for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
  9.     {
  10.         object? value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
  11.         array.SetValue(value, index);
  12.     }
  13.     return array;
  14. }
复制代码
VisitConstant
  1. protected override object? VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)        
  2. {            
  3.     //直接返回保存的实例
  4.     return constantCallSite.DefaultValue;        
  5. }
复制代码
VisitServiceProvider
  1. protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)        
  2. {            
  3.     return context.Scope;        
  4. }
复制代码
总结

先根据实例的生命周期进行分支判断,接下来根据服务的生成方式进行分支判断。


来源:https://www.cnblogs.com/ccwzl/archive/2023/07/24/17512617.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具