首页 > 其他分享 >.net core IOC容器实现(二) -- GetService

.net core IOC容器实现(二) -- GetService

时间:2023-06-21 23:35:28浏览次数:44  
标签:core serviceType return -- GetService callSite 实例 scope

使用IOC容器最重要的两个步骤就是注入服务和从容器内获取服务实例。上一节聊的ServiceDescriptor其实就可以看成注入服务的步骤,这一节初步聊一聊获取服务实例的相关源码。

  1. GetService
    GetService 方法是获取服务实例的入口,位于 ServiceProvider 这个类中
public object? GetService(Type serviceType) => GetService(serviceType, Root);

internal object? GetService(Type serviceType,
ServiceProviderEngineScope serviceProviderEngineScope)
{
    ...
    //如果有 realizedService 里有 ,获取,没有 就添加(serviceType 为key)  GetOrAdd(key,valueFactory) 根据key生成value
    Func<ServiceProviderEngineScope, object?> realizedService =
            _realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
    //检验能否解析
    ....
    //获取服务实例  此处的核心 是 CallSiteRuntimeResolver 类(负责根据 scope 进行服务解析)
    var result = realizedService.Invoke(serviceProviderEngineScope);
    ...
    return result;
}

从上面的代码可以看出,主要经历了两步,第一步根据 _createServiceAccessor 获取一个泛型委托,第二步使用泛型委托生成服务实例。

  1. _createServiceAccssor
    _createServiceAccssor 是获取
// 定义
private readonly Func<Type, Func<ServiceProviderEngineScope, object?>> _createServiceAccessor;
//初始化是在 ServiceProvider 的构造函数中
_createServiceAccessor = CreateServiceAccessor;
// CreateServiceAccessor 方法
private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType)
{
      //通过 服务类型 获取 callSite,CallSite 包含了如何生成服务实例的相关信息, 比如服务实例的生命周期
      ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
      if (callSite != null)
      {
              ...
               // Optimize singleton case  针对单例的优化
               if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
               {
                   //直接解析,如果callSite 里有,就直接返回 callSite 里存的值
                   object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
                   //以委托形式存下来
                   return scope => value;
               }
               //生成一个 可以通过 callSite 生成实例的委托
               return _engine.RealizeService(callSite);
        }
        return _ => null;
}

// 返回一个委托  Func<ServiceProviderEngineScope, object?>
// 该委托用途是生成 callSite 对应的servieType实例
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{
  int callCount = 0;
  return scope =>
  {
     var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
  }
}

首先通过CallSiteFactory获取一个一个callSite(在CallSiteFactory类中),可以先记住callSite作用是缓存和生成服务实例的细节,比如服务之间的依赖关系,如何创建实例的依赖。接下来则是根据服务的作用于范围,对单例做了优化,主要就是加了缓存(这个也是由callSite实现的),不用每次都去解析一次。如果不是单例,就需要结合callSite和_engine(scope相关)来获取服务了。但是从代码可以看出来无论是 Singleton 还是其他生命周期,最终调用的还是CallSiteRuntimeResolver.Instance.Resolve这个方法。

public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
  // Fast path to avoid virtual calls if we already have the cached value in the root scope
  // 如果在 root scope 范围里已经有缓存了,直接返回,也就是对单例的优化,缓存
  if (scope.IsRootScope && callSite.Value is object cached)
  {
    return cached;
  }
  //调用 VisitCallSite 进行解析
  return VisitCallSite(callSite, new RuntimeResolverContext
  {
    Scope = scope
  });
}

因为对单例做了缓存,所以如果已经解析过了,就会直接返回缓存里的值,否则就调用VisitCallSite进行解析。

VisitCallSite 这个方法打算放到下节,对这部分感兴趣的也可以自行先去看一看CallSiteRuntimeResolver这个类。

  1. 根据泛型委托生成服务实例,这个就是简单的调用委托
var result = realizedService.Invoke(serviceProviderEngineScope);

======================================

补充

  • ServiceCallSite, 可以看到里面有一个 Value,那个就是缓存的单例的值
internal abstract class ServiceCallSite
 {
     // 构建方式  实例,工厂,构造器
     public abstract CallSiteKind Kind { get; }
     //生命周期 和 cacheKey
     public ResultCache Cache { get; }
     //Singleton存放点
      public object? Value { get; set; }
 }

标签:core,serviceType,return,--,GetService,callSite,实例,scope
From: https://www.cnblogs.com/ccwzl/p/17490009.html

相关文章

  • Kali Linux 2023.2为Xfce版带来PipeWire支持
    Kali Linux 2023.2为Xfce版带来PipeWire支持,彻底改造i3桌面,这个版本还引入了一个新的Hyper-VVM镜像,以及几个新的黑客工具。OffensiveSecurity宣布了他们流行的道德黑客和渗透测试GNU/Linux发行版的新版本,带来了新的功能,更新和新的工具,以及许多改进,KaliLinux2023.2。......
  • Kali Linux 2023.2为Xfce版带来PipeWire支持
    Kali Linux 2023.2为Xfce版带来PipeWire支持,彻底改造i3桌面,这个版本还引入了一个新的Hyper-VVM镜像,以及几个新的黑客工具。OffensiveSecurity宣布了他们流行的道德黑客和渗透测试GNU/Linux发行版的新版本,带来了新的功能,更新和新的工具,以及许多改进,KaliLinux2023.2。......
  • c#动态执行字符串脚本
    c#动态执行字符串脚本(优化版)像javascript中有eval()来执行动态代码,c#中是没有的,于是自己动手丰衣足食,usingSystem;usingSystem.Data;usingSystem.Configuration;usingSystem.Text;usingSystem.CodeDom.Compiler;usingMicrosoft.CSharp;usingSystem.Reflection;us......
  • Kali Linux 2023.2为Xfce版带来PipeWire支持
    Kali Linux 2023.2为Xfce版带来PipeWire支持,彻底改造i3桌面,这个版本还引入了一个新的Hyper-VVM镜像,以及几个新的黑客工具。OffensiveSecurity宣布了他们流行的道德黑客和渗透测试GNU/Linux发行版的新版本,带来了新的功能,更新和新的工具,以及许多改进,KaliLinux2023.2。......
  • The final
    TheendT1构造题n/k为偶数很好构造,每组直接前面拿n/k/2个,后面拿n/k/2个n/k为奇数需要想一想,首先可以把1~n分成n/k段,每段选一个放到一组里,按照以上方法处理n/k-3段,使每组各数之和相等。再来看前三段,可以把第三段提出来,用前1,2段构造一个等差数列。如何构造?只需要找到需要的等差......
  • 【剑指Offer】35、数组中的逆序对
    【剑指Offer】35、数组中的逆序对题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。即输出P%1000000007。输入描述:题目保证输入的数组中没有的相同的数......
  • 容器运行时及其命令
    ContainerRuntime负责容器的整个生命周期。k8s1.5之后,k8s通过CRI(容器运行时接口)对接“容器运行时”  为何弃用dockerdocker使用的容器运行时containerd。本身是符合CRI标准的。之前:k8s->dockershim(k8s维护)->docker->containerd->oci->container*n......
  • 代码随想录Day32|贪心II
     今日任务●  122.买卖股票的最佳时机II ●  55. 跳跃游戏 ●  45.跳跃游戏II ●  1005.K次取反后最大化的数组和 ●  134. 加油站●  135. 分发糖果 122.买卖股票的最佳时机IIclassSolution:defmaxProfit(self,prices:List[int]......
  • ethercat调试
    1.日鼎伺服无法上电状态字始终是0x2306041状态字(官方手册P50)bit15bit14bit13bit12bit11bit10bit9bit8bit7bit6bit5bit4bit3bit2bit1bit0厂家自定义特殊的运行模式内部限制行为目标到达远程参数厂家自定义报警开机去使能急停上电使能故障运行使能开机准备开机......
  • 【数据结构与算法】用队列实现栈
    ......