追风猎人 发表于 2023-7-25 01:54:39

.net core IOC 容器实现(四) -- CallSiteRuntimeResolver

上一节聊了一下 CallSite 是怎样生成的,这一节我们来看一下 CallSite 是如何使用的。
入口

先让我们来回顾一下CreateServiceAccessor 这个方法。
private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType)      
{
    //通过 服务类型 获取 callSite         
    ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());            
    if (callSite != null)         
    {                           
      if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)               
      {               
            //直接解析   
            object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);                                 
      }                     
      return _engine.RealizeService(callSite);            
    }
}这段代码跟 CallSite 有关的一共有三个地方,分别是 GetCallSite 和 Resolve(callSite,Root)以及 _engine.RealizeService。其中 GetCallSite 是用来生成 CallSite 的(也就是上一节的主要内容),而剩下的两个则是对于 CallSite 的使用,也是这一节的主要内容。
RealizeService

我们先看一下 _engine.RealizeService 方法。
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{                     
    return scope =>            
    {               
      var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);                     
      return result;            
    };      
}我们可以发现最终调用的还是 CallSiteRuntimeResolver.Instance.Resolve 这个方法,所以其实归根结底对 CallSite 的调用其实最终就是一个地方,也就是这个 Resolve 方法。
CallSiteRuntimeResolver.Resolve

public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
    // 如果在 root scope 范围里已经有缓存了,直接返回
    if (scope.IsRootScope && callSite.Value is object cached)
    {
      return cached;
    }
    //调用 VisitCallSite 进行解析
    return VisitCallSite(callSite, new RuntimeResolverContext
    {
      Scope = scope
    });
}VisitCallSite

protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
    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();
    }
}VisitCallSite 会根据 Location 进行分支处理,Location 是 CallSite 里的一个属性。其中 Root 对应 Singleton,Scope 对应 Scope 生命周期,Dispose 对应 Trasient,None可以先将其理解为Singleton。
VisitRootCache(Single)

protected override object? VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
{
    // Singleton 懒加载 如果有 value 直接返回         
    if (callSite.Value is object value)
    {
      // Value already calculated, return it directly
      return value;
    }

    var lockType = RuntimeResolverLock.Root;
    //在 root 范围进行解析
    ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
    // 锁住 callSite 防止重复生成value

    lock (callSite)
    {
      // Lock the callsite and check if another thread already cached the value
      // 可能其他地方已经生成了,在获取一下看看      
      if (callSite.Value is object callSiteValue)
      {
            return callSiteValue;
      }
      //最终依旧是调用了 VisitCallSiteMain 方法

      object? resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
      {
            Scope = serviceProviderEngine,
            AcquiredLocks = context.AcquiredLocks | lockType
      });
      serviceProviderEngine.CaptureDisposable(resolved);
      //进行缓存
      callSite.Value = resolved;
      return resolved;
    }
}VisitScopeCache(Scope)

// Check if we are in the situation where scoped service was promoted to singleton
// and we need to lock the root
// Scope 依赖 Singleton
return context.Scope.IsRootScope ?
    VisitRootCache(callSite, context) :
    VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);private object? VisitCache(
    ServiceCallSite callSite,
    RuntimeResolverContext context,
    ServiceProviderEngineScope serviceProviderEngine,
    RuntimeResolverLock lockType)
{
    bool lockTaken = false;
    object sync = serviceProviderEngine.Sync;
    // Dictionary<ServiceCacheKey, object?> ResolvedServices { get; } 缓存
    Dictionary<ServiceCacheKey, object?> resolvedServices = serviceProviderEngine.ResolvedServices;
    // Taking locks only once allows us to fork resolution process
    // on another thread without causing the deadlock because we
    // always know that we are going to wait the other thread to finish before
    // releasing the lock
    // 锁住 sync 对象
    if ((context.AcquiredLocks & lockType) == 0)
    {
      Monitor.Enter(sync, ref lockTaken);
    }
    try
    {
      //获取锁之后
      // Note: This method has already taken lock by the caller for resolution and access synchronization.
      // For scoped: takes a dictionary as both a resolution lock and a dictionary access lock.
      //先访问缓存
      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;
    }
    finally
    {
      //解锁
      if (lockTaken)
      {
            Monitor.Exit(sync);
      }
    }
}VisitDisposeCache(Transient)

protected override object? VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)      
{   
    //解析      
    var instance=VisitCallSiteMain(transientCallSite, context);
    return context.Scope.CaptureDisposable(instance);      
}VisitNoCache(None)

protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
{
    return VisitCallSiteMain(callSite, argument);
}VisitCallSiteMain

观察以上方法,我们可以发现无论是 VisitRootCache还是VisitScopeCache 等等,最终都是调用 VisitCallSiteMain 这个方法来生成的实例。
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
    //callSite.kind 是只读属性 ,在 GetCallSite 时确定,根据 CallSite 类型确定(例 ConstantCallSite)
    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()));
    }
}VisitConstructor

其中比较复杂的就是这个 VisitConstructor 方法,通过反射来构造实例,主要思路是拿到实例类型的构造函数,然后通过递归(调用VisitCallSite(见本文最上方))准备构造函数所需要的参数,最后调用 invoke 来生成实例。
protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
{
    object?[] parameterValues;
    //获取构造需要使用的参数
    //无参
    if (constructorCallSite.ParameterCallSites.Length == 0)
    {
      parameterValues = Array.Empty<object>();
    }
    //有参
    else
    {
      parameterValues = new object?;
      for (int index = 0; index < parameterValues.Length; index++)
      {
            //递归解析 VisitCallSite 见上文
            parameterValues = VisitCallSite(constructorCallSite.ParameterCallSites, context);
      }
    }
#if NETFRAMEWORK || NETSTANDARD2_0
            try
            {
                return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
            }
            catch (Exception ex) when (ex.InnerException != null)
            {
                ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                // The above line will always throw, but the compiler requires we throw explicitly.
                throw;
            }
#else
    return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null,
                                                      parameters: parameterValues, culture: null);
#endif
}VisitFactory

protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
{
    //调用Factory(Func<IServiceProvider, object> Factory) 委托(委托由开发者实现)
    return factoryCallSite.Factory(context.Scope);
}VisitIEnumerable

protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
{
    //创建枚举类型的数组
    var array = Array.CreateInstance(
      enumerableCallSite.ItemType,
      enumerableCallSite.ServiceCallSites.Length);                           

    //给数组填充值
    for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
    {
      object? value = VisitCallSite(enumerableCallSite.ServiceCallSites, context);
      array.SetValue(value, index);
    }
    return array;
}VisitConstant

protected override object? VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)      
{            
    //直接返回保存的实例
    return constantCallSite.DefaultValue;      
}VisitServiceProvider

protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)      
{            
    return context.Scope;      
}总结

先根据实例的生命周期进行分支判断,接下来根据服务的生成方式进行分支判断。


来源:https://www.cnblogs.com/ccwzl/archive/2023/07/24/17512617.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: .net core IOC 容器实现(四) -- CallSiteRuntimeResolver