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

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

原创
作者头像
莫问今朝
发布2018-11-29 08:23:07
3450
发布2018-11-29 08:23:07
举报
文章被收录于专栏:博客园博客园
代码语言:txt
复制
`CallSiteRuntimeResolver`类型是一个创建或获取服务实例的类型,这个类型继承了`CallSiteVisitor<TArgument, TResult>`这个类型,也是使用了访问者模式,下面一一来解析此类

ServiceProviderEngineScope

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

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

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

代码语言:txt
复制
internal class ServiceProviderEngineScope : IServiceScope, IServiceProvide

{

       private List<IDisposable> \_disposables;

       private bool \_disposed;

}
代码语言:txt
复制
在此类中还具有两个属性,一个是缓存实例对象的集合和一个\*\*ServiceProviderEngine\*\*类型的属性,从下面可以看出缓存集合使用了是`ServiceCacheKey`作为缓存的key,
代码语言:txt
复制
而Engine是引擎类型,此属性通过构造函数传入,并且所有容器共享一个`ServiceProviderEngine`,也就是共享容器共享注册的服务    
代码语言:txt
复制
//    缓存的实例对象集合

internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; } = new Dictionary<ServiceCacheKey, object>();

//    所有ServiceProviderEngineScope对象共享一个ServiceProviderEngine

public ServiceProviderEngine Engine { get; }



//     构造函数

 public ServiceProviderEngineScope(ServiceProviderEngine engine)=> Engine = engine;
代码语言:txt
复制
这个类中一共具有四个方法,

* GetService():获取对象,可以看到此方法调用的**Engine**的**GetService()**,这个方法到ServiceProviderEngine时再看

* ServiceProvider():这个方法返回的是当前对象

* Dispose():释放当前容器,可以看到在释放当前容器时会把**_disposables**集合中所有实例进行释放,并把**_disposed**属性设置*TRUE*

* CaptureDisposable():这个方法缓存要被的释放的服务实例

代码语言:txt
复制
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;

}

CallSiteRuntimeResolve

代码语言:txt
复制
上面说过`CallSiteRuntimeResolver`这个类型是创建和获取服务实例类型的访问者,这个类型泛型参数分别为`RuntimeResolverContext`类型和实例对象类型`Object`
代码语言:txt
复制
internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>{}
代码语言:txt
复制
`RuntimeResolverContext`类型是一个`ServiceProviderEngineScope`封装类型,这个类型中具有一个`ServiceProviderEngineScope`类型属性和一个`RuntimeResolverLock`枚举类型属性,这个枚举类型在实例化对象时当做了锁使用
代码语言:txt
复制
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>基类中

代码语言:txt
复制
//        根据服务对象的生命周期进行访问访问实例

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:

代码语言:txt
复制
   这个方法是访问\*\*Root\*\*生命周期的方法,可以看到这个在这个方法调用了一个\*\*VisitCache()\*\*,这个方法一共四个参数,第一个,第二个分别是当前方法函数。第三个参数代表容器对象,容器使用的是`ServiceProviderEngine`实例中的\*\*Root\*\*属性,这个容器代表了顶级容器,<span style="color:red">\*\*这也就是Root生命周期的本质,使用的顶级容器进行创建/获取实例\*\*</span>,第四个参数锁,此方法使用的是\*\*RuntimeResolverLock.Root\*\*锁

* ##### VisitScopeCache:

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

* ##### VisitDisposeCache

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

* ##### VisitNoCache

代码语言:txt
复制
  这个方法代表不缓存,这个方法在`CallSiteRuntimeResolver`类中未重写,所以直接调用的`CallSiteVisitor`类型的\*\*VisitNoCache()\*\*,也基类中直接调用\*\*VisitCallSiteMain()\*\*
代码语言:txt
复制
////        CallSiteRuntimeResolve

//        访问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));



////        CallSiteVisito

//        无缓存

 protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)

      => VisitCallSiteMain(callSite, argument);
代码语言:txt
复制
\*\*VisitCache()\*\*这个方法是使用指定的容器进行实例化并缓存服务实例对象,在下面代码中可以看到,代码中根据\*\*RuntimeResolverContext\*\*实例的枚举值与第四个参数进行,如果不相同,则进行加锁。然后进行获取实例服务对象,如果已缓存则直接获取,没有缓存则调用\*\*VisitCallSiteMain()\*\*获取实例并缓存
代码语言:txt
复制
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);

     }

}
代码语言:txt
复制
\*\*VisitCallSiteMain()\*\*内调用的所有方法都在`CallSiteRuntimeResolver`类进行了重写,下面看看`CallSiteRuntimeResolve`类中的这些方法

* ##### VisitFactory

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

* ##### VisitIEnumerable

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

* ##### ConstructorCallSite

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

* ##### ConstantCallSite

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

* ##### VisitServiceProvide

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

* ##### VisitServiceScopeFactory

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

代码语言:txt
复制
//      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;
代码语言:txt
复制
在`CallSiteRuntimeResolver`中还有叫做\*\*Resolve()\*\*,这个方法则是外部调用的,这个方法是由一个`ServiceCallSite`对象和一个容器对象`ServiceProviderEngineScope`,然后直接调用\*\*VisitCallSite()\*\*进行方法,可以看到调用此方法时\*\*AcquiredLocks\*\*属性并未赋值.
代码语言:txt
复制
public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)

{

     return VisitCallSite(callSite, new RuntimeResolverContext

                          {

                               Scope = scope

                          });

}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

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