ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Net6 DI源码分析Part4 CallSiteFactory ServiceCallSite

2022-02-09 11:35:42  阅读:165  来源: 互联网

标签:CallSiteFactory DI callSiteChain CallSiteChain descriptor 源码 CallSiteResultCache


Net6 CallSiteFactory ServiceCallSite, CallSiteChain
abstract class ServiceCallSite

ServiceCallSite是个抽象类,实现ConstantCallSite、ConstructorCallSite、 FactoryCallSite、ServiceProviderCallSite、IEnumerableCallSite ServiceCallSite对一个服务的描述,CallSiteFactory提供了它的构建。engine就是根据此类的描述来进行创建对应的服务。

public abstract Type ServiceType { get; }
public abstract Type? ImplementationType { get; }
public abstract CallSiteKind Kind { get; }
public ResultCache Cache { get; }
public object? Value { get; set; }
public bool CaptureDisposable =>
CallSiteFactory

可以说整个DI中它最忙了。它的作用是为engine提供一个描述服务信息的ServiceCallSite对象。

  1. CallSiteFactory(ICollection descriptors)

    1. 创建了个堆栈卫士
    2. copy一份ICollection给_descriptors
    3. 调用Populate整理出Dictionary<Type, ServiceDescriptorCacheItem> _descriptorLookup
  2. Populate()

    1. 做了一系列验证并把验证后的数据添加到Dictionary<Type, ServiceDescriptorCacheItem> _descriptorLookup
  3. ServiceCallSite? GetCallSite(Type serviceType, CallSiteChain callSiteChain)

    1. 先去缓存拿_callSiteCache.TryGetValue 如果又直接返回。
    2. 走CreateCallSite流程
      1. 会走堆栈卫士
      2. CreateCallSite会为每个type类型做个锁
      3. callSiteChain.CheckCircularDependency(serviceType); 参考CallSiteChain
      4. 创建ServiceCallSite
        1. TryCreateExact // 普通的
        2. TryCreateOpenGeneric// 泛型的
        3. TryCreateEnumerable // 同一个类型注册了多个的。
  4. ServiceCallSite? GetCallSite(ServiceDescriptor serviceDescriptor, CallSiteChain callSiteChain)

    1. 此方法是个重载方法,其内部直接调用TryCreateExact(TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot))与另外一个GetCallSite相比,此方法跳过了堆栈卫士,以及锁,和先从缓存_callSiteCache拿的过程。所以速度更快。也仅用于初始化验证使用,但是TryCreateExact内部调用链中也会调用 CreateArgumentCallSites这样就又使用到第一个重载方法了。也会从新走堆栈卫士等等一系列的操作。算是相对优化。
  5. ServiceCallSite? TryCreateExact(Type serviceType, CallSiteChain callSiteChain)

    1. 拿到对应的ServiceDescriptor交给重载方法。
  6. ServiceCallSite? TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)

    1. 根据ServiceDescriptor创建CallSite(ConstantCallSite/ImplementationFactory/ ConstructorCallSite)用户就涉及到这三种类型。其余的是系统用的。

        if (descriptor.ImplementationInstance != null)
        {
            callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance);
        }
        else if (descriptor.ImplementationFactory != null)
        {
            callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);
        }
        else if (descriptor.ImplementationType != null)
        {
            callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain);
        }
      

      主要是CreateConstructorCallSite的创建比较特殊。。

      1. 调用CreateConstructorCallSite → CreateArgumentCallSites → GetCallSite → 递归回TryCreateExact的调用;
    2. 缓存并返回

  7. CreateConstructorCallSite 准备出一个需要DI“new”出来的一个实例的ConstructorCallSite对象,

    1. 先确认是否有可以用的构造函数。没有肯定抛错误了
    2. 如果只有一个构造函数,且没有参数,拿就简单了直接new 一个ConstructorCallSite返回
    3. 如果只有一个构造函数,有构造参数,获取参数列表并调用 CreateArgumentCallSites 且内部递归调用回GetCallSite
    4. 如果有多个构造参数。找出一个合适的构造函数
      1. 根据构造函数的参数数量做了个降序Array.Sort(constructors,(a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length));
      2. 参数最多的构造函数
      3. 校验其余构造函数参数内是否有被选构造函数没有的参数,如果存在没有的参数就抛异常。
  8. ServiceCallSite[]? CreateArgumentCallSites( Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)

    1. 内部循环递归调用GetCallSite(parameterType, callSiteChain);并创建一个ServiceCallSite[]返回。
CallSiteChain

它的出现就是为了防止构造函数形式提供服务时循环依赖项 比如服务A的构造方法依赖服务B,服务B的构造方法又依赖函数A。 以下为两个关键节点。

  1. CreateCallSite时先确认 CreateCallSite → callSiteChain.CheckCircularDependency()
  2. 以构造方法模式创建对象时进行累加。CreateConstructorCallSite ⇒ callSiteChain.Add(serviceType, implementationType)

伪代码调用过着如下

    1. CallSiteFactory.CreateCallSite(serviceType, new callSiteChain()) => callSiteChain.CheckCircularDependency(); => GetCallSite();
           GetCallSite => TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) => CreateConstructorCallSite
                 CreateConstructorCallSite => callSiteChain.Add(serviceType, implementationType) ; CreateArgumentCallSites;
                    CreateArgumentCallSites => 递归回GetCallSite();

CallSiteKind

描述CallSiteService类别的枚举 Factory,Constructor,Constant,IEnumerable,ServiceProvider, 在CallSiteVisitor.VisitCallSiteMain根据此枚举去调用对应创建实例的Visit方法 如VisitFactory/VisitIEnumerable/VisitConstructor/VisitConstant/ VisitServiceProvider/

CallSiteResultCacheLocation

描述创建好的服务缓存位子,也对应着服务注册时的生命周期。。 在CallSiteVisitor->VisitCallSite根据此枚举去调用不同的VisitCache 如VisitRootCache/VisitScopeCache switch (lifetime) { case ServiceLifetime.Singleton: Location = CallSiteResultCacheLocation.Root; break; case ServiceLifetime.Scoped: Location = CallSiteResultCacheLocation.Scope; break; case ServiceLifetime.Transient: Location = CallSiteResultCacheLocation.Dispose; break; default: Location = CallSiteResultCacheLocation.None; break; }

ResultCache

用来描述CallSiteService 对ServiceCacheKey/CallSiteResultCacheLocation 的封装。

internal struct ResultCache
    {
        public ResultCache(ServiceLifetime lifetime, Type type, int slot)
        {
            switch (lifetime)
            {
                case ServiceLifetime.Singleton:
                    Location = CallSiteResultCacheLocation.Root;
                    break;
                case ServiceLifetime.Scoped:
                    Location = CallSiteResultCacheLocation.Scope;
                    break;
                case ServiceLifetime.Transient:
                    Location = CallSiteResultCacheLocation.Dispose;
                    break;
                default:
                    Location = CallSiteResultCacheLocation.None;
                    break;
            }
            Key = new ServiceCacheKey(type, slot);
        }
 
        public CallSiteResultCacheLocation Location { get; set; }
 
        public ServiceCacheKey Key { get; set; }
    }
ServiceCacheKey
1. CallSiteFacotry根据此类型去缓存CallSiteServie。
2. ServiceProviderEngineScope根据此类型去缓存 ResolvedServices
CallSiteValidator

//以下没啥好说的。

ConstantCallSite
ConstructorCallSite
FactoryCallSite
IEnumerableCallSite
ServiceProviderCallSite

标签:CallSiteFactory,DI,callSiteChain,CallSiteChain,descriptor,源码,CallSiteResultCache
来源: https://www.cnblogs.com/hts92/p/15818053.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有