CallSiteRuntimeResolver

CallSiteRuntimeResolver是实现了CallSiteVisitor之一。

提供的方法主要分三个部分

  1. 自有成员方法

    1. Resolve提供服务
    2. VisitCache
    3. 私有构造函数
  2. 重写父类方法

    1. VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)

      调用父类VisitCallSiteMain ,并把创建出来的服务添加到context.Scope.CaptureDisposable

      return context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
    2. object VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)

      1. 先找对应callSite.Value是否有值如果有直接返回
      2. 如果没有直接调用 VisitCallSiteMain创建服务并把对象rootServiceProviderEngine内。
      3. 创建的服务放入callSite.Value。
          if (callSite.Value is object value)
      {
      return value;
      } var lockType = RuntimeResolverLock.Root;
      ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
      if (callSite.Value is object resolved)
      {
      return resolved;
      }
      resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
      {
      Scope = serviceProviderEngine,
      AcquiredLocks = context.AcquiredLocks | lockType
      });
      serviceProviderEngine.CaptureDisposable(resolved);
      callSite.Value = resolved;
      return resolved;
    3. VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)

      1. 先去serviceProviderEngine.resolvedServices拿,有的话直接返回如果没拿到执行步骤2去创建。serviceProviderEngine.resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved)
      2. VisitCallSiteMain创建对象
      3. 把创建后的对象加入对应Scope的 disposable列表
      4. 把创建后的对象加入对应Scope的 resolvedServices列表
          if (resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved))
      {
      return resolved;
      }
      resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
      {
      Scope = serviceProviderEngine,
      AcquiredLocks = context.AcquiredLocks | lockType
      });
      serviceProviderEngine.CaptureDisposable(resolved);
      resolvedServices.Add(callSite.Cache.Key, resolved);
      return resolved;
  3. 实现父类抽象方法

    1. VisitConstructor

      1. 给构造方法提供参数(如果有参数递归调用VisitCallSite创建参数对象)
      2. 直接调用ServiceCallSite的ConstructorInfo反射创建对象。
         object[] parameterValues;
      if (constructorCallSite.ParameterCallSites.Length == 0)
      {
      parameterValues = Array.Empty<object>();
      }
      else
      {
      parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
      for (int index = 0; index < parameterValues.Length; index++)
      {
      parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
      }
      } return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameterValues, culture: null);
    2. override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)

      直接返回CallSite对象的DefaultValue

      return constantCallSite.DefaultValue;
    3. VisitServiceProvider

      return context.Scope;
    4. override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)

      根据ServiceCallSites直接循环调用VisitCallSite创建实例,然后根据实例创建集合返回
        var array = Array.CreateInstance(
      enumerableCallSite.ItemType,
      enumerableCallSite.ServiceCallSites.Length);
      for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
      {
      object value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
      array.SetValue(value, index);
      }
      return array;
    5. VisitFactory

      return factoryCallSite.Factory(context.Scope);

体力活都给CallSiteFactory

CallSiteVisitor
  1. 方法

    1. VisitCallSite(ServiceCallSite callSite, TArgument argument)

      1. 保证Stack安全
      2. 根据callSite的Cache.Location去调用不同策略的Cache方法。
      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();
      }
    2. VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)

      1. 根据不同CallSiteKind去调用不同策略的创建服务方法。
         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);
        default:
        throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
        }
  2. 虚方法
    1. TResult VisitNoCache(ServiceCallSite callSite, TArgument argument) => VisitCallSiteMain(callSite, argument);
    2. TResult VisitDisposeCache(ServiceCallSite callSite, TArgument argument) -> isitCallSiteMain(callSite, argument);
    3. TResult VisitRootCache(ServiceCallSite callSite, TArgument argument) -> VisitCallSiteMain(callSite, argument);
    4. TResult VisitScopeCache(ServiceCallSite callSite, TArgument argument) => VisitCallSiteMain(callSite, argument);

    根据生命周期策略由子类实现对应存储机制。

  3. 抽象方法
    1. TResult VisitConstructor(ConstructorCallSite constructorCallSite, TArgument argument);
    2. TResult VisitConstant(ConstantCallSite constantCallSite, TArgument argument);
    3. TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument);
    4. TResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, TArgument argument);
    5. TResult VisitFactory(FactoryCallSite factoryCallSite, TArgument argument);

    根据服务注册时的创建机制策略由子类实现对应的创建对象机制。

CallSiteVisitor负责这活怎么干!。CallSiteRuntimeResolver负责干活

  1. 调用 VisitCallSite在内部区分出scope并调用具体实现方法缓存方法 (CallSiteResultCacheLocation),

    -> VisitCache方法

    -> 但是在缓存前得先得到被缓存的对象,这时通过调用(VisitCallSiteMain)创建对象

    -> VisitCallSiteMain根据提供的callsite类型去调用实现的抽象方法创建对应对象

    -> 根据cache对应的方法缓存步骤1.1的结果。
  2. return cahce的结果。
整体的获取对象流程大约如下

CallSiteRuntimeResolver.Resolve -> CallSiteVisitor->VisitCallSite callSite.Cache.Location VisitRootCache/VisitScopeCache/ VisitDisposeCache/ VisitNoCache -> CallSiteRuntimeResolver.VisitCache/ VisitRootCache -> VisitRootCache -> CallSiteVisitor.VisitCallSiteMain 根据callSite.Kind CallSiteRuntimeResolver.VisitFactory(abstract TResult VisitFactory)递归调用 VisitCallSite

Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor的更多相关文章

  1. Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的?

    Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的? 在asp.net core中的DI生命周期有一个Scoped是根据请求走的,也就是说在处理一次请求时, ...

  2. Net6 DI源码分析Part4 CallSiteFactory ServiceCallSite

    Net6 CallSiteFactory ServiceCallSite, CallSiteChain abstract class ServiceCallSite ServiceCallSite是个 ...

  3. Net6 DI源码分析Part2 Engine,ServiceProvider

    ServiceProvider ServiceProvider是对IServiceProvider实现,它有一个internal的访问修饰符描述的构造,并需要两个参数IServiceCollectio ...

  4. Net6 DI源码分析Part1 ServiceCollection、ServiceDescriptor、ServiceLifetime、IServiceProvider

    ServiceCollection.ServiceDescriptor.ServiceLifetime.IServiceProvider Microsoft.Extensions.Dependency ...

  5. Net6Configuration & Options 源码分析 Part3 IOptionsMonitor 是如何接收到配置文件变更并同步数据源的

    配置源的同步 IOptionsMonitor 使用 //以下demo演示使用IOptionsMonitor重新加载配置并当重新加载配置是执行回调函数 var configuration = new C ...

  6. 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析

    目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...

  7. Net6 Configuration & Options 源码分析 Part2 Options

    Net6 Configuration & Options 源码分析 Part2 Options 第二部分主要记录Options 模型 OptionsConfigurationServiceCo ...

  8. 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器

    1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...

  9. Net6 Configuration & Options 源码分析 Part1

    Net6 Configuration & Options 源码分析 Part1 在Net6中配置系统一共由两个部分组成Options 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...

随机推荐

  1. 深入 Laravel 内核之 PHP 反射机制和依赖注入

    结论: PHP中提供了反射类来解析类的结构: 通过反射类可以获取到类的构造函数及其参数和依赖: 给构造函数的参数递归设置默认值后,即可使用这些带默认值的参数通过 newInstanceArgs 实例化 ...

  2. bind 标签

    <select id="finduserbylikename"  parameterType="string"  resultMap="cour ...

  3. Leetcode算法系列(链表)之两数相加

    Leetcode算法系列(链表)之两数相加 难度:中等给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果,我们将 ...

  4. Linux基础之终端、控制台、tty、pty简介说明

    最近在搞Linux提权的时候,有时候su 用户名 登录的时候发现登录不了,因为tty终端,交互不了,所以我也来总结一下 一. 基本概念 1. ttytty(终端设备的统称):tty一词源于telety ...

  5. IPX下载安装

    IPX下载安装 该软件需要事先安装LAPACK与openblas,相关安装教程请点击链接. 1.下载 mkdir IPX cd IPX git clone https://github.com/ERG ...

  6. Solon Web 开发,十三、WebSocket

    Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...

  7. ClassCastException: java.util.Date cannot be cast to java.sql.Date

    解决办法 /** * 单个方法,作用,根据输入的day:yyyy-mm-dd格式的字符日期,将数据库中的该天所有数据更新为0 * 0表示假期 * @param day * @throws SQLExc ...

  8. 1月29日 体温APP开发记录

    1.阅读构建之法 现代软件工程(第三版) 2.观看Android开发视频教程最新版 Android Studio开发 3.高德地图API下载获取key  

  9. 【小记录】android命令行程序发生coredump后读取堆栈信息

    一开始执行: adb shell cd /data/local/tmp ulimit -c unlimited ./xxx 然后查看coredump文件信息: adb pull /data/local ...

  10. 返回值Student处理过程