- A+
上一节聊了一下 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?[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; }
总结
先根据实例的生命周期进行分支判断,接下来根据服务的生成方式进行分支判断。