類型是一個創建或獲取服務實例的類型,這個類型繼承了 這個類型,也是使用了訪問者模式,下麵一一來解析此類 ServiceProviderEngineScope 在解析 之前先看一下 類型,這個類型就可以是一個容器類型,最後實例化的服務對象就緩存在此類之中, 從下麵代碼中可以看出此類實現了 和`IS ...
CallSiteRuntimeResolver
類型是一個創建或獲取服務實例的類型,這個類型繼承了CallSiteVisitor<TArgument, TResult>
這個類型,也是使用了訪問者模式,下麵一一來解析此類
ServiceProviderEngineScope
在解析`CallSiteRuntimeResolver`之前先看一下`ServiceProviderEngineScope`類型,這個類型就可以是一個容器類型,最後實例化的服務對象就緩存在此類之中,
從下麵代碼中可以看出此類實現了`IServiceScope`和`IServiceProvider`兩個介面,並且此類型擁有兩個欄位
_disposables:IDisposabl集合,此欄位緩存的時所有實現了IDisposable介面的註冊服務,以便在釋放此容器實例時並將這些服務一起釋放
_disposed:判斷此屬性是否已被是否釋放
internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
{
private List<IDisposable> _disposables;
private bool _disposed;
}
在此類中還具有兩個屬性,一個是緩存實例對象的集合和一個**ServiceProviderEngine**類型的屬性,從下麵可以看出緩存集合使用了是`ServiceCacheKey`作為緩存的key,
而Engine是引擎類型,此屬性通過構造函數傳入,並且所有容器共用一個`ServiceProviderEngine`,也就是共用容器共用註冊的服務
// 緩存的實例對象集合
internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; } = new Dictionary<ServiceCacheKey, object>();
// 所有ServiceProviderEngineScope對象共用一個ServiceProviderEngine
public ServiceProviderEngine Engine { get; }
// 構造函數
public ServiceProviderEngineScope(ServiceProviderEngine engine)=> Engine = engine;
這個類中一共具有四個方法,
- GetService():獲取對象,可以看到此方法調用的Engine的GetService(),這個方法到
ServiceProviderEngine
時再看- ServiceProvider():這個方法返回的是當前對象
- Dispose():釋放當前容器,可以看到在釋放當前容器時會把**_disposables集合中所有實例進行釋放,並把_disposed**屬性設置TRUE
- CaptureDisposable():這個方法緩存要被的釋放的服務實例
public object GetService(Type serviceType)
{
if (_disposed)
// 如果已被釋放,就不能調用此方法
ThrowHelper.ThrowObjectDisposedException();
return Engine.GetService(serviceType, this);
}
public IServiceProvider ServiceProvider => this;
public void Dispose()
{
lock (ResolvedServices)
{
if (_disposed)
return;
_disposed = true;
if (_disposables != null)
{
for (var i = _disposables.Count - 1; i >= 0; i--)
{
var disposable = _disposables[i];
disposable.Dispose();
}
_disposables.Clear();
}
ResolvedServices.Clear();
}
}
// 緩存所有需要清理的服務實例
internal object CaptureDisposable(object service)
{
if (!ReferenceEquals(this, service))
{
if (service is IDisposable disposable)
{
lock (ResolvedServices)
{
if (_disposables == null)
_disposables = new List<IDisposable>();
_disposables.Add(disposable);
}
}
}
return service;
}
CallSiteRuntimeResolver
上面說過CallSiteRuntimeResolver
這個類型是創建和獲取服務實例類型的訪問者,這個類型泛型參數分別為RuntimeResolverContext
類型和實例對象類型Object
internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>{}
RuntimeResolverContext
類型是一個ServiceProviderEngineScope
封裝類型,這個類型中具有一個ServiceProviderEngineScope
類型屬性和一個RuntimeResolverLock
枚舉類型屬性,這個枚舉類型在實例化對象時當做了鎖使用
internal struct RuntimeResolverContext
{
public ServiceProviderEngineScope Scope { get; set; }
// 鎖
public RuntimeResolverLock AcquiredLocks { get; set; }
}
[Flags]
internal enum RuntimeResolverLock
{
Scope = 1,
Root = 2
}
在CallSiteRuntimeResolver
類型中擁有兩類方法,
- 根據註冊服務的生命周期進行訪問服務實例對象
- 根據ServiceCallSite的設置類型進行訪問服務實例對象
這兩個類都在其CallSiteVisitor<TArgument, TResult>
基類中
// 根據服務對象的生命周期進行訪問訪問實例
protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
// 緩存位置由ServiceCallSite內部的Cache屬性的Location提供
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();
}
}
// 根據其ServiceCallSite的Kind屬性訪問服務對象
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
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);
case CallSiteKind.ServiceScopeFactory:
return VisitServiceScopeFactory((ServiceScopeFactoryCallSite)callSite, argument);
default:
throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported");
}
}
這兩個方法內部調用的方法部分被CallSiteRuntimeResolver
類中重寫,
下麵先來看看根據生命周期進行訪問的一系列方法
VistRootCache:
這個方法是訪問Root生命周期的方法,可以看到這個在這個方法調用了一個VisitCache(),這個方法一共四個參數,第一個,第二個分別是當前方法函數。第三個參數代表容器對象,容器使用的是
ServiceProviderEngine
實例中的Root屬性,這個容器代表了頂級容器,這也就是Root生命周期的本質,使用的頂級容器進行創建/獲取實例,第四個參數鎖,此方法使用的是RuntimeResolverLock.Root鎖VisitScopeCache:
這個方法是訪問Scoped生命周期方法,此方法和上面方法相似,也是調用了VisitCache(),但是不同的是是鎖不同,這個鎖是根據當前容器來決定,如果當前容器為頂級容器,就使用Root鎖,所以不為頂級容器,則使用Scope鎖
VisitDisposeCache
這個方法訪問transient生命周期方法,可以看到這個方法直接調用VisitCallSiteMain()進行獲取實例對象,然後調用CaptureDisposable()將此對象嘗試緩存到ServiceProviderEngineScope容器的**_disposables**集合中
VisitNoCache
這個方法代表不緩存,這個方法在
CallSiteRuntimeResolver
類中未重寫,所以直接調用的CallSiteVisitor
類型的VisitNoCache(),也基類中直接調用VisitCallSiteMain()
//// CallSiteRuntimeResolver
// 訪問Root生命周期方法
protected override object VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
=> VisitCache(singletonCallSite, context, context.Scope.Engine.Root, RuntimeResolverLock.Root);
// 訪問Scoped生命周期方法
protected override object VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
{
// 如果當前容器為根容器,則將其鎖轉換為Root,否則為Scope
var requiredScope = context.Scope == context.Scope.Engine.Root ?
RuntimeResolverLock.Root :
RuntimeResolverLock.Scope;
return VisitCache(singletonCallSite, context, context.Scope, requiredScope);
}
// 訪問transient生命周期方法
protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
=> context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
//// CallSiteVisitor
// 無緩存
protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
=> VisitCallSiteMain(callSite, argument);
**VisitCache()**這個方法是使用指定的容器進行實例化並緩存服務實例對象,在下麵代碼中可以看到,代碼中根據**RuntimeResolverContext**實例的枚舉值與第四個參數進行,如果不相同,則進行加鎖。然後進行獲取實例服務對象,如果已緩存則直接獲取,沒有緩存則調用**VisitCallSiteMain()**獲取實例並緩存
private object VisitCache(ServiceCallSite scopedCallSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
{
bool lockTaken = false;
// 獲取容器中的緩存服務實例屬性
var resolvedServices = serviceProviderEngine.ResolvedServices;
if ((context.AcquiredLocks & lockType) == 0)
// 如果當前枚舉值與RuntimeResolverContext的枚舉值不相同,則加鎖
Monitor.Enter(resolvedServices, ref lockTaken);
try
{
// 如果當前數據並未在緩存之中,則實例化此對象並將其緩存至集合中
if (!resolvedServices.TryGetValue(scopedCallSite.Cache.Key, out var resolved))
{
// 獲取實例對象
resolved = VisitCallSiteMain(scopedCallSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
// 將當前對象嘗試加入到容器的_disposables集合
serviceProviderEngine.CaptureDisposable(resolved);
// 緩存實例對象
resolvedServices.Add(scopedCallSite.Cache.Key, resolved);
}
return resolved;
}
finally
{
if (lockTaken)
Monitor.Exit(resolvedServices);
}
}
**VisitCallSiteMain()**內調用的所有方法都在`CallSiteRuntimeResolver`類進行了重寫,下麵看看`CallSiteRuntimeResolve`類中的這些方法
VisitFactory
在VisitFactory()中直接調用了
FactoryCallSite
實例對象的工廠方法獲取實例VisitIEnumerable
在VisitIEnumerable()中實例了
IEnumerableCallSite
中ServiceCallSites集合的所有對象,並組裝到一個數組進行返回ConstructorCallSite
在VisitConstructor()中使用反射方法實例化對象,並且如果構造函數不為空則獲取所有參數的實例對象
ConstantCallSite
在VisitConstant()中直接返回了
ConstantCallSite
中的對象VisitServiceProvider
在VisitServiceProvider()直接返回了
RuntimeResolverContext
封裝的容器VisitServiceScopeFactory
在VisitServiceScopeFactory()中則直接返回了容器實例中引擎對象(ServiceProviderEngine)
// FactoryCallSite
protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
// 調用工廠方法進行實例化
=> factoryCallSite.Factory(context.Scope);
// IEnumerableCallSite
protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
{
var array = Array.CreateInstance(
enumerableCallSite.ItemType,
enumerableCallSite.ServiceCallSites.Length);
for (var index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
{
// 實例化IEnumerableCallSite.ServiceCallSites中所有的服務實例對象並賦值到數組中
var value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
array.SetValue(value, index);
}
return array;
}
// ConstructorCallSite
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 (var index = 0; index < parameterValues.Length; index++)
parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
}
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;
}
}
// ConstantCallSite
protected override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
// 直接返回ConstantCallSite的值
=> constantCallSite.DefaultValue;
// ServiceProviderCallSite
protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)
// 直接返回RuntimeResolverContext封裝的容器
=> context.Scope;
// ServiceScopeFactoryCallSite
protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, RuntimeResolverContext context)
// 直接返回容器內的ServiceProviderEngine
=> context.Scope.Engine;
在`CallSiteRuntimeResolver`中還有叫做**Resolve()**,這個方法則是外部調用的,這個方法是由一個`ServiceCallSite`對象和一個容器對象`ServiceProviderEngineScope`,然後直接調用**VisitCallSite()**進行方法,可以看到調用此方法時**AcquiredLocks**屬性並未賦值.
public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
return VisitCallSite(callSite, new RuntimeResolverContext
{
Scope = scope
});
}