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. Ubuntu16.04下,erlang安装和rabbitmq安装步骤

    文章来源: Ubuntu16.04下,erlang安装和rabbitmq安装步骤 准备工作,先下载erlang和rabbitmq的安装包,注意他们的版本,版本不对可能会导致rabbitmq无法启动,这 ...

  2. centos7 自动交互expect 安装使用

    1.安装 https://www.cnblogs.com/rocky-AGE-24/p/7256800.html 安装expect命令 两种方式yum安装 yum -y install expect ...

  3. 安装KVM

    在VMWare安装CentOS7 选择图形界面和开发工具 设置网络 cd /etc/sysconfig/network-scripts/ vi ifcfg-ens33 BOOTPROTO=static ...

  4. Pandas系列(十七)-EDA(pandas-profiling)

    对于探索性数据分析来说,做数据分析前需要先看一下数据的总体概况,pandas_profiling工具可以快速预览数据. 安装 pip install pandas-profiling 使用 impor ...

  5. PPT制作手机手指滑动效果

    原文链接:https://www.toutiao.com/i6495304998786695694/ 上一节我们完成了手机滑动粗糙效果,这部分我们将给动画添加一个手指的图片. 首先,选择"插 ...

  6. 信不信由你!iPhone6屏幕宽度不一定是375px,iPhone6 Plus屏幕宽度不一定是414px

    看到这个题目你可能不信,引出这个问题的缘由是几次项目中Chrome模拟器和iPhone6真机预览效果不一致. 为什么在Chrome Emulation模拟手机页面和真机预览效果不一致? 以前觉得不外乎 ...

  7. 计算机视觉2-> 深度学习 | anaconda+cuda+pytorch环境配置

    00 想说的 深度学习的环境我配置了两个阶段,暑假的时候在一个主攻视觉的实验室干活,闲暇时候就顺手想给自己的Ubuntu1804配置一个深度学习的环境.这会儿配到了anaconda+pytorch+c ...

  8. 简单Spring MVC项目搭建

    1.新建Project 开发环境我使用的是IDEA,其实使用什么都是大同小异的,关键是自己用的顺手. 首先,左上角File→New→Project.在Project页面选择Maven,然后勾上图中所示 ...

  9. RISC-V CPU加电执行流程

    市面上采用RISC-V架构的CPU很多,且没有如X86那样高度细节的标准,故采用说明文档详细的SiFive Freedom U540-C000芯片来做介绍(下面统一称为FU540). FU540支持多 ...

  10. leetcode 264. 丑数 II 及 313. 超级丑数

    264. 丑数 II 题目描述 编写一个程序,找出第 n 个丑数. 丑数就是只包含质因数 2, 3, 5 的正整数. 示例: 输入: n = 10 输出: 12 解释: 1, 2, 3, 4, 5, ...