zoukankan      html  css  js  c++  java
  • Core官方DI解析(4)--CallSiteRuntimeResolver

    CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用了访问者模式,下面一一来解析此类

    ServiceProviderEngineScope

    在解析`CallSiteRuntimeResolver`之前先看一下`ServiceProviderEngineScope`类型,这个类型就可以是一个容器类型,最后实例化的服务对象就缓存在此类之中,
    
    从下面代码中可以看出此类实现了`IServiceScope`和`IServiceProvider`两个接口,并且此类型拥有两个字段
    

    _disposables:IDisposabl集合,此字段缓存的时所有实现了IDisposable接口的注册服务,以便在释放此容器实例时并将这些服务一起释放

    _disposed:判断此属性是否已被是否释放

    internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
    {
           private List<IDisposable> _disposables;
           private bool _disposed;
    }
    
    在此类中还具有两个属性,一个是缓存实例对象的集合和一个**ServiceProviderEngine**类型的属性,从下面可以看出缓存集合使用了是`ServiceCacheKey`作为缓存的key,
    
    而Engine是引擎类型,此属性通过构造函数传入,并且所有容器共享一个`ServiceProviderEngine`,也就是共享容器共享注册的服务	
    
    //    缓存的实例对象集合
    internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; } = new Dictionary<ServiceCacheKey, object>();
    //    所有ServiceProviderEngineScope对象共享一个ServiceProviderEngine
    public ServiceProviderEngine Engine { get; }
    
    //	 构造函数
     public ServiceProviderEngineScope(ServiceProviderEngine engine)=> Engine = engine;
    
    这个类中一共具有四个方法,
    
    • GetService():获取对象,可以看到此方法调用的EngineGetService(),这个方法到ServiceProviderEngine时再看
    • ServiceProvider():这个方法返回的是当前对象
    • Dispose():释放当前容器,可以看到在释放当前容器时会把_disposables集合中所有实例进行释放,并把_disposed属性设置TRUE
    • CaptureDisposable():这个方法缓存要被的释放的服务实例
    public object GetService(Type serviceType)
    {
         if (_disposed)
              //		如果已被释放,就不能调用此方法
              ThrowHelper.ThrowObjectDisposedException();
         return Engine.GetService(serviceType, this);
    }
    
    public IServiceProvider ServiceProvider => this;
    
    public void Dispose()
    {
         lock (ResolvedServices)
         {
              if (_disposed)
                   return;
              _disposed = true;
              if (_disposables != null)
              {
                   for (var i = _disposables.Count - 1; i >= 0; i--)
                   {
                        var disposable = _disposables[i];
                        disposable.Dispose();
                   }
    
                   _disposables.Clear();
              }
    
              ResolvedServices.Clear();
         }
    }
    //  缓存所有需要清理的服务实例
    internal object CaptureDisposable(object service)
    {
    
         if (!ReferenceEquals(this, service))
         {
              if (service is IDisposable disposable)
              {
                   lock (ResolvedServices)
                   {
                        if (_disposables == null)
                             _disposables = new List<IDisposable>();
                        _disposables.Add(disposable);
                   }
              }
         }
         return service;
    }
    

    CallSiteRuntimeResolver

    ​ 上面说过CallSiteRuntimeResolver这个类型是创建和获取服务实例类型的访问者,这个类型泛型参数分别为RuntimeResolverContext类型和实例对象类型Object

    internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>{}
    

    RuntimeResolverContext类型是一个ServiceProviderEngineScope封装类型,这个类型中具有一个ServiceProviderEngineScope类型属性和一个RuntimeResolverLock枚举类型属性,这个枚举类型在实例化对象时当做了锁使用

    internal struct RuntimeResolverContext
    {
         public ServiceProviderEngineScope Scope { get; set; }
         //		锁
         public RuntimeResolverLock AcquiredLocks { get; set; }
    }
    [Flags]
    internal enum RuntimeResolverLock
    {
         Scope = 1,
         Root = 2
    }
    

    CallSiteRuntimeResolver类型中拥有两类方法,

    • 根据注册服务的生命周期进行访问服务实例对象
    • 根据ServiceCallSite的设置类型进行访问服务实例对象

    这两个类都在其CallSiteVisitor<TArgument, TResult>基类中

    //		根据服务对象的生命周期进行访问访问实例
    protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
    {
         //	缓存位置由ServiceCallSite内部的Cache属性的Location提供
         switch (callSite.Cache.Location)
         {
              case CallSiteResultCacheLocation.Root:
                   return VisitRootCache(callSite, argument);
              case CallSiteResultCacheLocation.Scope:
                   return VisitScopeCache(callSite, argument);
              case CallSiteResultCacheLocation.Dispose:
                   return VisitDisposeCache(callSite, argument);
              case CallSiteResultCacheLocation.None:
                   return VisitNoCache(callSite, argument);
              default:
                   throw new ArgumentOutOfRangeException();
         }
    }
    
    //		根据其ServiceCallSite的Kind属性访问服务对象
    protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
    {
         switch (callSite.Kind)
         {
              case CallSiteKind.Factory:
                   return VisitFactory((FactoryCallSite)callSite, argument);
              case  CallSiteKind.IEnumerable:
                   return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
              case CallSiteKind.Constructor:
                   return VisitConstructor((ConstructorCallSite)callSite, argument);
              case CallSiteKind.Constant:
                   return VisitConstant((ConstantCallSite)callSite, argument);
              case CallSiteKind.ServiceProvider:
                   return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
              case CallSiteKind.ServiceScopeFactory:
                   return VisitServiceScopeFactory((ServiceScopeFactoryCallSite)callSite, argument);
              default:
                   throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported");
         }
    }
    

    ​这两个方法内部调用的方法部分被CallSiteRuntimeResolver类中重写,

    下面先来看看根据生命周期进行访问的一系列方法

    • VistRootCache:

      这个方法是访问Root生命周期的方法,可以看到这个在这个方法调用了一个VisitCache(),这个方法一共四个参数,第一个,第二个分别是当前方法函数。第三个参数代表容器对象,容器使用的是ServiceProviderEngine实例中的Root属性,这个容器代表了顶级容器,这也就是Root生命周期的本质,使用的顶级容器进行创建/获取实例,第四个参数锁,此方法使用的是RuntimeResolverLock.Root

    • VisitScopeCache:

      这个方法是访问Scoped生命周期方法,此方法和上面方法相似,也是调用了VisitCache(),但是不同的是是锁不同,这个锁是根据当前容器来决定,如果当前容器为顶级容器,就使用Root锁,所以不为顶级容器,则使用Scope

    • VisitDisposeCache

      这个方法访问transient生命周期方法,可以看到这个方法直接调用VisitCallSiteMain()进行获取实例对象,然后调用CaptureDisposable()将此对象尝试缓存到ServiceProviderEngineScope容器的_disposables集合中

    • VisitNoCache

      这个方法代表不缓存,这个方法在CallSiteRuntimeResolver类中未重写,所以直接调用的CallSiteVisitor类型的VisitNoCache(),也基类中直接调用VisitCallSiteMain()

    
    ////		CallSiteRuntimeResolver
    //		访问Root生命周期方法
    protected override object VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
          => VisitCache(singletonCallSite, context, context.Scope.Engine.Root, RuntimeResolverLock.Root);
    //		访问Scoped生命周期方法
    protected override object VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
    {
         //      如果当前容器为根容器,则将其锁转换为Root,否则为Scope
         var requiredScope = context.Scope == context.Scope.Engine.Root ?
              RuntimeResolverLock.Root :
         RuntimeResolverLock.Scope;
         return VisitCache(singletonCallSite, context, context.Scope, requiredScope);
    }
    //		访问transient生命周期方法
    protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
          => context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
    
    ////		CallSiteVisitor
    //		无缓存
     protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
          => VisitCallSiteMain(callSite, argument);
    
    **VisitCache()**这个方法是使用指定的容器进行实例化并缓存服务实例对象,在下面代码中可以看到,代码中根据**RuntimeResolverContext**实例的枚举值与第四个参数进行,如果不相同,则进行加锁。然后进行获取实例服务对象,如果已缓存则直接获取,没有缓存则调用**VisitCallSiteMain()**获取实例并缓存
    
    private object VisitCache(ServiceCallSite scopedCallSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
    {
         bool lockTaken = false;
         //      获取容器中的缓存服务实例属性
         var resolvedServices = serviceProviderEngine.ResolvedServices;
         if ((context.AcquiredLocks & lockType) == 0)
       		 //      如果当前枚举值与RuntimeResolverContext的枚举值不相同,则加锁
              Monitor.Enter(resolvedServices, ref lockTaken);
         try
         {
              //      如果当前数据并未在缓存之中,则实例化此对象并将其缓存至集合中
              if (!resolvedServices.TryGetValue(scopedCallSite.Cache.Key, out var resolved))
              {
                   //      获取实例对象
                   resolved = VisitCallSiteMain(scopedCallSite, new RuntimeResolverContext
                                                {
                                                     Scope = serviceProviderEngine,
                                                     AcquiredLocks = context.AcquiredLocks | lockType
                                                });
                   //      将当前对象尝试加入到容器的_disposables集合
                   serviceProviderEngine.CaptureDisposable(resolved);
                   //      缓存实例对象
                   resolvedServices.Add(scopedCallSite.Cache.Key, resolved);
              }
              return resolved;
         }
         finally
         {
              if (lockTaken)
              	Monitor.Exit(resolvedServices);
         }
    }
    
    **VisitCallSiteMain()**内调用的所有方法都在`CallSiteRuntimeResolver`类进行了重写,下面看看`CallSiteRuntimeResolve`类中的这些方法
    
    • VisitFactory

      VisitFactory()中直接调用了FactoryCallSite实例对象的工厂方法获取实例

    • VisitIEnumerable

      VisitIEnumerable()中实例了IEnumerableCallSiteServiceCallSites集合的所有对象,并组装到一个数组进行返回

    • ConstructorCallSite

      VisitConstructor()中使用反射方法实例化对象,并且如果构造函数不为空则获取所有参数的实例对象

    • ConstantCallSite

      VisitConstant()中直接返回了ConstantCallSite中的对象

    • VisitServiceProvider

      VisitServiceProvider()直接返回了RuntimeResolverContext封装的容器

    • VisitServiceScopeFactory

      VisitServiceScopeFactory()中则直接返回了容器实例中引擎对象(ServiceProviderEngine)

    //      FactoryCallSite
    protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
         //		调用工厂方法进行实例化
         => factoryCallSite.Factory(context.Scope);
    
    //		IEnumerableCallSite
    protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
    {
         var array = Array.CreateInstance(
              enumerableCallSite.ItemType,
              enumerableCallSite.ServiceCallSites.Length);
         for (var index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
         {
              //		实例化IEnumerableCallSite.ServiceCallSites中所有的服务实例对象并赋值到数组中
              var value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
              array.SetValue(value, index);
         }
         return array;
    }
    
    //		ConstructorCallSite
    protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
    {
         object[] parameterValues;
         if (constructorCallSite.ParameterCallSites.Length == 0)
              parameterValues = Array.Empty<object>();
         else
         {
              //		如果当前构造器参数不为空,则实例化每一个参数的实例对象
              parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
              for (var index = 0; index < parameterValues.Length; index++)
                   parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
         }
         try
         {
              //		根据参数对象进行实例化对象并返回
              return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
         }
         catch (Exception ex) when (ex.InnerException != null)
         {
              ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
              // The above line will always throw, but the compiler requires we throw explicitly.
              throw;
         }
    }
    
    //		ConstantCallSite
     protected override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
          //		直接返回ConstantCallSite的值
          => constantCallSite.DefaultValue;
    
    //		ServiceProviderCallSite
    protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context) 
         //		直接返回RuntimeResolverContext封装的容器
         => context.Scope;
    
    //		ServiceScopeFactoryCallSite
     protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, RuntimeResolverContext context)
          //		直接返回容器内的ServiceProviderEngine
          => context.Scope.Engine;
    
    在`CallSiteRuntimeResolver`中还有叫做**Resolve()**,这个方法则是外部调用的,这个方法是由一个`ServiceCallSite`对象和一个容器对象`ServiceProviderEngineScope`,然后直接调用**VisitCallSite()**进行方法,可以看到调用此方法时**AcquiredLocks**属性并未赋值.
    
    public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
    {
         return VisitCallSite(callSite, new RuntimeResolverContext
                              {
                                   Scope = scope
                              });
    }
    
  • 相关阅读:
    操作系统面试题(四)
    计算机网络面试题(三)
    redis和mongodb面试题(一)
    MySQL面试题(二)
    数据库基础面试题(一)
    RoBERTa模型总结
    BERT模型总结
    动态规划-Dynamic Programming(DP)
    XGBoost原理学习总结
    re模块的使用
  • 原文地址:https://www.cnblogs.com/yan7/p/10036148.html
Copyright © 2011-2022 走看看