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

发布时间 2023-07-24 23:58:26作者: zydxpc

上一节聊了一下 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 有关的一共有三个地方,分别是 GetCallSiteResolve(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?[constructorCallSite.ParameterCallSites.Length];
        for (int index = 0; index < parameterValues.Length; index++)
        {
            //递归解析 VisitCallSite 见上文
            parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], 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[index], 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;        
}

总结

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