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

  • .net core IOC 容器实现(四) — CallSiteRuntimeResolver已关闭评论
  • 198 次浏览
  • A+
所属分类:.NET技术
摘要

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

上一节聊了一下 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;         } 

总结

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

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