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. javascript实现base64格式转码与解码

    最近碰到一个需求,后端返回base64格式的数据,前端需要进行base64格式解码,好了,前端采用内部提供的atob函数进行解码,开完成,交付测试,然后测试小哥哥小姐姐反馈说中文乱码! 然后查了一下, ...

  2. Dom 键盘事件以及实战案例

    键盘事件 //键盘操作 //1.某键盘按下执行的操作 document是对文档进行触发 document.onkeyup = function(){ console.log('你好') } docum ...

  3. CAD快速入门--绝望

    从入门到放弃 咱是革命一块砖,哪里需要哪里搬.(需求来自领导,让我一个敲代码的画CAD图纸,可以想象我在一个什么样的公司,在为什么样的老板赚钱,不多说了下面开始学习). CAD绘图功能优化与基本操作 ...

  4. Linux shell 脚本中使用 alias 定义的别名

    https://www.cnblogs.com/chenjo/p/11145021.html 核心知识点: 用 shopt 开启和关闭 alias 扩展 交互模式下alias 扩展默认是开启的,脚本模 ...

  5. 利用ajaxfileupload插件异步上传文件

    html代码: <input type="file" id="imgFile" name="imgFile" /> js代码: ...

  6. layui type:2 iframe子页面向父页面传值

    需求: 选择子页面表格中的radio或者双击该行,得到的该行数据传到父页面,由父页面渲染. 网上的各种方法都用了,父页面就是获取不到子页面传的值,过了一晚上,睡了一觉,柳暗花明又一村. layui t ...

  7. 第51篇-SharedRuntime::generate_native_wrapper()生成编译入口

    当某个native方法被调用时,一开始它会从解释入口进入,也就是我之前介绍的.由InterpreterGenerator::generate_native_entry()函数生成的入口例程.在这个例程 ...

  8. 展示html/javascript/css------Live-Server服务器

    Live-server简介 这是一款带有热加载功能的小型开发服务器.用它来展示你的HTML / JavaScript / CSS,但不能用于部署最终的网站. 官网地址:https://www.npmj ...

  9. 代码审计入门之BlueCMS v1.6 sp1

    0x00 前言 作为一名代码审计的新手,网上的大佬们说代码审计入门的话BlueCMS比较好,所以我就拿BlueCMS练练.(本人实在是一枚新手,请大佬们多多赐教) 0x01 环境准备 Phpstudy ...

  10. 图解GNN:A Gentle Introduction to Graph Neural Networks

    1.图是什么? 本文给出得图的定义为:A graph represents the relations (edges) between a collection of entities (nodes) ...