前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Core官方DI解析(4)--CallSiteRuntimeResolver

Core官方DI解析(4)--CallSiteRuntimeResolver

作者头像
莫问今朝
发布2018-12-19 16:25:47
2940
发布2018-12-19 16:25:47
举报
文章被收录于专栏:博客园博客园博客园

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
                          });
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-11-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ServiceProviderEngineScope
  • CallSiteRuntimeResolver
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档