翼度科技»论坛 编程开发 .net 查看内容

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

7

主题

7

帖子

21

积分

新手上路

Rank: 1

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

  • GetService
    GetService 方法是获取服务实例的入口,位于 ServiceProvider 这个类中
  1. public object? GetService(Type serviceType) => GetService(serviceType, Root);
  2. internal object? GetService(Type serviceType,
  3. ServiceProviderEngineScope serviceProviderEngineScope)
  4. {
  5.     ...
  6.     //如果有 realizedService 里有 ,获取,没有 就添加(serviceType 为key)  GetOrAdd(key,valueFactory) 根据key生成value
  7.     Func<ServiceProviderEngineScope, object?> realizedService =
  8.             _realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
  9.     //检验能否解析
  10.     ....
  11.     //获取服务实例  此处的核心 是 CallSiteRuntimeResolver 类(负责根据 scope 进行服务解析)
  12.     var result = realizedService.Invoke(serviceProviderEngineScope);
  13.     ...
  14.     return result;
  15. }
复制代码
从上面的代码可以看出,主要经历了两步,第一步根据 _createServiceAccessor 获取一个泛型委托,第二步使用泛型委托生成服务实例。

  • _createServiceAccssor
    _createServiceAccssor 是获取
  1. // 定义
  2. private readonly Func<Type, Func<ServiceProviderEngineScope, object?>> _createServiceAccessor;
  3. //初始化是在 ServiceProvider 的构造函数中
  4. _createServiceAccessor = CreateServiceAccessor;
  5. // CreateServiceAccessor 方法
  6. private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType)
  7. {
  8.       //通过 服务类型 获取 callSite,CallSite 包含了如何生成服务实例的相关信息, 比如服务实例的生命周期
  9.       ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
  10.       if (callSite != null)
  11.       {
  12.               ...
  13.                // Optimize singleton case  针对单例的优化
  14.                if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
  15.                {
  16.                    //直接解析,如果callSite 里有,就直接返回 callSite 里存的值
  17.                    object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
  18.                    //以委托形式存下来
  19.                    return scope => value;
  20.                }
  21.                //生成一个 可以通过 callSite 生成实例的委托
  22.                return _engine.RealizeService(callSite);
  23.         }
  24.         return _ => null;
  25. }
  26. // 返回一个委托  Func<ServiceProviderEngineScope, object?>
  27. // 该委托用途是生成 callSite 对应的servieType实例
  28. public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
  29. {
  30.   int callCount = 0;
  31.   return scope =>
  32.   {
  33.      var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
  34.   }
  35. }
复制代码
首先通过CallSiteFactory获取一个一个callSite(在CallSiteFactory类中),可以先记住callSite作用是缓存和生成服务实例的细节,比如服务之间的依赖关系,如何创建实例的依赖。接下来则是根据服务的作用于范围,对单例做了优化,主要就是加了缓存(这个也是由callSite实现的),不用每次都去解析一次。如果不是单例,就需要结合callSite和_engine(scope相关)来获取服务了。但是从代码可以看出来无论是 Singleton 还是其他生命周期,最终调用的还是CallSiteRuntimeResolver.Instance.Resolve这个方法。
  1. public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
  2. {
  3.   // Fast path to avoid virtual calls if we already have the cached value in the root scope
  4.   // 如果在 root scope 范围里已经有缓存了,直接返回,也就是对单例的优化,缓存
  5.   if (scope.IsRootScope && callSite.Value is object cached)
  6.   {
  7.     return cached;
  8.   }
  9.   //调用 VisitCallSite 进行解析
  10.   return VisitCallSite(callSite, new RuntimeResolverContext
  11.   {
  12.     Scope = scope
  13.   });
  14. }
复制代码
因为对单例做了缓存,所以如果已经解析过了,就会直接返回缓存里的值,否则就调用VisitCallSite进行解析。
VisitCallSite 这个方法打算放到下节,对这部分感兴趣的也可以自行先去看一看CallSiteRuntimeResolver这个类。

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

  • ServiceCallSite, 可以看到里面有一个 Value,那个就是缓存的单例的值
  1. internal abstract class ServiceCallSite
  2. {
  3.      // 构建方式  实例,工厂,构造器
  4.      public abstract CallSiteKind Kind { get; }
  5.      //生命周期 和 cacheKey
  6.      public ResultCache Cache { get; }
  7.      //Singleton存放点
  8.       public object? Value { get; set; }
  9. }
复制代码
来源:https://www.cnblogs.com/ccwzl/archive/2023/06/21/17490009.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具