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
                          });
}

原文地址:https://www.cnblogs.com/yan7/p/10036148.html

时间: 2024-10-16 11:53:29

Core官方DI解析(4)--CallSiteRuntimeResolver的相关文章

Core官方DI解析(3)-ServiceCallSite.md

上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象方法,所以我们先来看看其它的类型 ServiceCallSite ServiceCallSite ? 这个是一个服务访问配置的类型,DI内部使用此类的派生类型进行封装所需要实例化的信息然后进行实例化服务对象,首先我们先来看一下ServiceCallSite这个类所拥有的属性.从下面可以看到Servi

ASPNET CORE 的 DI 依赖注入 及 AuotoFac 的引入

学习有关Aspnet Core 的DI及IOC等,参考: 1.全面理解 ASP.NET Core 依赖注入    https://blog.csdn.net/hiliqi/article/details/80611209 提及 AuotoFac 的引入Aspnet Core的方式: 把Startup类里面的 ConfigureService的 返回值从 void改为 IServiceProvider即可. public IServiceProvider ConfigureServices(   

Android应用之——谷歌官方Json解析工具Gson的使用

一.Gson简介 Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为串行化Java对象为JSON字符串,或反串行化JSON字符串成Java对象.也就是Java对象与json字符串间的互相转换,解析. 二.使用方法 Gson的应用主要为toJson与fromJson两个转换函数,而在使用这种对象转换之前需先创建好对象的类型以及其成员才能成功的将JSON字符串成功转换成相对应的对象.即先创建好对应的javabean,javabean中的字段与要转换的

Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)

Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5) 相关资料:1.http://blog.csdn.net/laorenshen/article/details/411498032.http://www.cnblogs.com/findumars/p/5149128.html 一.理清概念1.蓝牙设备:是指代有蓝牙通信的手机.电脑.平板.打印机.耳机等.2.设备名称:是指设备打开蓝牙功能后,在其他设备中显示的名字,如图1用的A.B.C等.3.蓝牙关态:如果A手机没有

实战Asp.Net Core:DI生命周期

原文:实战Asp.Net Core:DI生命周期 title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使用 DI 的过程中,我们势必会接触到对象的生命周期,那么几种不同的对象生命周期到底是怎么样的呢?我们拿代码说话. 关于 DI 与 IOC: 个人理解:IOC(控制反转) 是目的(降低代码.服务间的耦合),而 DI 是达到该目的的一种手段(具体办法).

ASP.NET Core官方计划路线及需要废除的一些Framework技术

概述 下面是 ASP.NET Core的时间表和路线图. 注意日期和特性都可能更改. 作为.NET Core这么大的一个项目,很难准确预测每一个计划的是否有变动. 即便如此,我们还是计划公开和透明的实施,以便我们的用户可以有正确的期望值, 并为我们的用户自己在技术实施时有更好的打算和安排 发布时间表 Release 发布日志 1.1 Q4 2016 / Q1 2017 1.2 Q1 2017 / Q2 2017 Release 版本特性 1.1 URL 重写中间件 Response 缓存中间件

Android开源库--Gson谷歌官方json解析库

官方文档地址:http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/index.html 官方网站:http://code.google.com/p/google-gson/ json官方网站:http://www.json.org/json-zh.html 目前主流数据传输都用的是json,解析json并且转换成相应的类型就成了必经之路. 在没有使用gson之前,原生Andoird自带有类解析json,但是实在不方便使用.

.NET Core HtmlAgilityPack HTML解析利器

最近学习.NET Core ,想把自己之前的一个项目升级到 .NET Core. 发现HtmlAgilityPack 没法进行引用,遂自己做了些修改,可以运行在 .NET Core 中.现在分享出来,也是为  .NET Core 做一些贡献. .NET Core版 HtmlAgilityPack HTML解析利器,目前是 HtmlAgilityPack Core RC2 HtmlAgilityPack 介绍 HtmlAgilityPack是一个基于.Net的.第三方免费开源的微型类库,主要用于在

ActivityLifeCycle官方demo解析

1.关于Activity的生命周期的几篇文章: http://1.duoinfo.sinaapp.com/?p=330 http://1.duoinfo.sinaapp.com/?p=332 http://1.duoinfo.sinaapp.com/?p=335 http://1.duoinfo.sinaapp.com/?p=337 training课程给的图是这样的: 2.运行官方的程序 看到这个demo含有四个Activity,最后一个Activity的样式文件为dialog.并且在下面用T