經過前幾篇文章的講解,初步瞭解ASP.NET Core MVC項目創建,啟動運行,以及命名約定,創建控制器,視圖,模型,接收參數,傳遞數據ViewData,ViewBag,路由,頁面佈局,wwwroot和客戶端庫,Razor語法,EnityFrameworkCore與資料庫,HttpContext,... ...
使用IOC容器最重要的兩個步驟就是註入服務和從容器內獲取服務實例。上一節聊的ServiceDescriptor其實就可以看成註入服務的步驟,這一節初步聊一聊獲取服務實例的相關源碼。
- GetService
GetService 方法是獲取服務實例的入口,位於 ServiceProvider 這個類中
public object? GetService(Type serviceType) => GetService(serviceType, Root);
internal object? GetService(Type serviceType,
ServiceProviderEngineScope serviceProviderEngineScope)
{
...
//如果有 realizedService 里有 ,獲取,沒有 就添加(serviceType 為key) GetOrAdd(key,valueFactory) 根據key生成value
Func<ServiceProviderEngineScope, object?> realizedService =
_realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
//檢驗能否解析
....
//獲取服務實例 此處的核心 是 CallSiteRuntimeResolver 類(負責根據 scope 進行服務解析)
var result = realizedService.Invoke(serviceProviderEngineScope);
...
return result;
}
從上面的代碼可以看出,主要經歷了兩步,第一步根據 _createServiceAccessor
獲取一個泛型委托,第二步使用泛型委托生成服務實例。
- _createServiceAccssor
_createServiceAccssor 是獲取
// 定義
private readonly Func<Type, Func<ServiceProviderEngineScope, object?>> _createServiceAccessor;
//初始化是在 ServiceProvider 的構造函數中
_createServiceAccessor = CreateServiceAccessor;
// CreateServiceAccessor 方法
private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType)
{
//通過 服務類型 獲取 callSite,CallSite 包含瞭如何生成服務實例的相關信息, 比如服務實例的生命周期
ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
...
// Optimize singleton case 針對單例的優化
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
{
//直接解析,如果callSite 里有,就直接返回 callSite 里存的值
object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
//以委托形式存下來
return scope => value;
}
//生成一個 可以通過 callSite 生成實例的委托
return _engine.RealizeService(callSite);
}
return _ => null;
}
// 返回一個委托 Func<ServiceProviderEngineScope, object?>
// 該委托用途是生成 callSite 對應的servieType實例
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{
int callCount = 0;
return scope =>
{
var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
}
}
首先通過CallSiteFactory獲取一個一個callSite(在CallSiteFactory
類中),可以先記住callSite作用是緩存和生成服務實例的細節,比如服務之間的依賴關係,如何創建實例的依賴。接下來則是根據服務的作用於範圍,對單例做了優化,主要就是加了緩存(這個也是由callSite實現的),不用每次都去解析一次。如果不是單例,就需要結合callSite和_engine(scope相關)來獲取服務了。但是從代碼可以看出來無論是 Singleton 還是其他生命周期,最終調用的還是CallSiteRuntimeResolver.Instance.Resolve
這個方法。
public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
// Fast path to avoid virtual calls if we already have the cached value in the root scope
// 如果在 root scope 範圍里已經有緩存了,直接返回,也就是對單例的優化,緩存
if (scope.IsRootScope && callSite.Value is object cached)
{
return cached;
}
//調用 VisitCallSite 進行解析
return VisitCallSite(callSite, new RuntimeResolverContext
{
Scope = scope
});
}
因為對單例做了緩存,所以如果已經解析過了,就會直接返回緩存里的值,否則就調用VisitCallSite
進行解析。
VisitCallSite
這個方法打算放到下節,對這部分感興趣的也可以自行先去看一看CallSiteRuntimeResolver
這個類。
- 根據泛型委托生成服務實例,這個就是簡單的調用委托
var result = realizedService.Invoke(serviceProviderEngineScope);
======================================
補充
- ServiceCallSite, 可以看到裡面有一個 Value,那個就是緩存的單例的值
internal abstract class ServiceCallSite
{
// 構建方式 實例,工廠,構造器
public abstract CallSiteKind Kind { get; }
//生命周期 和 cacheKey
public ResultCache Cache { get; }
//Singleton存放點
public object? Value { get; set; }
}