接著 上篇 目前也算是交代清楚了相關的類。那麼框架具體是如何來實例化的呢?整個的流程是怎麼樣的。 我們參考源碼中的Test文件夾來看看: var collection = new ServiceCollection(); collection.AddTransient<DependOnNonexis ...
接著 上篇 目前也算是交代清楚了相關的類。那麼框架具體是如何來實例化的呢?整個的流程是怎麼樣的。
我們參考源碼中的Test文件夾來看看:
var collection = new ServiceCollection(); collection.AddTransient<DependOnNonexistentService>(); var provider = CreateServiceProvider(collection); protected override IServiceProvider CreateServiceProvider(IServiceCollection collection) => collection.BuildServiceProvider(); public static ServiceProvider BuildServiceProvider(this IServiceCollection services) { return BuildServiceProvider(services, ServiceProviderOptions.Default); } public class ServiceProviderOptions { // Avoid allocating objects in the default case internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions(); /// <summary> /// <c>true</c> to perform check verifying that scoped services never gets resolved from root provider; otherwise <c>false</c>. /// </summary> public bool ValidateScopes { get; set; } internal ServiceProviderMode Mode { get; set; } = ServiceProviderMode.Dynamic; } internal enum ServiceProviderMode { Dynamic, Runtime, Expressions, ILEmit } public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options) { if (services == null) { throw new ArgumentNullException(nameof(services)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } return new ServiceProvider(services, options); } internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options) { IServiceProviderEngineCallback callback = null; if (options.ValidateScopes) { callback = this; _callSiteValidator = new CallSiteValidator(); } switch (options.Mode) { case ServiceProviderMode.Dynamic: _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); break; case ServiceProviderMode.Runtime: _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); break; #if IL_EMIT case ServiceProviderMode.ILEmit: _engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback); break; #endif case ServiceProviderMode.Expressions: _engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback); break; default: throw new NotSupportedException(nameof(options.Mode)); } }View Code
如上所示,就是註入服務,實例化服務的整個過程了。我們主要是根據IServiceCollection的擴展方法BuilServiceProvider調用ServiceProvider類,進而實例化相關服務。
除去這種方式實現ServiceProvider外,預設asp.net core框架中還有一個DefaultServiceProviderFactory。不過這個工廠類最後也是調用IServiceCollection介面的拓展方法--BuildServiceProvider來創建ServiceProvider類。
總結:
IServiceCollection介面的拓展方法Addxxx 收集需要註入的服務,服務實現類型,服務的生命周期。這些就是在ServiceDescriptor中獲取到的,也是該類的屬性對象。這個也是IServiceCollection繼承自IList<ServiceDescriptor>的解釋所在。隨後再獲取ServiceProviderOptions枚舉對象,選擇實現實例化的類型,比如反射等。最後就是調用BuildServiceProvider來生成ServiceProvider了。ServiceProvider根據選擇之前的選擇及配置,實例化服務。
除去最後使用反射等來實例化服務之外,可以看出asp.net core的DI框架的設計思路是這樣的:
將需要服務對象抽象化,首先,一個服務要進行DI,需要知道的是服務對象,實例對象,服務生命周期。將這三點抽象成一個ServiceDescriptor服務描述符對象。
由於需要DI的服務有很多,因此抽象出來一個容器來存儲每個服務的三大對象(我們只敘述重要,常用的三個對象),也就是我們上面抽象出來的描述符對象。這個容器我們使用ServiceCollection來表示,它繼承自IServiceCollection,而IServiceCollection其實就是IList<ServiceDescriptor>的集合,代表著眾多的註入服務。服務的實例化我們抽象出來一個類:ServiceProvider,它實現一個介面,該介面只有一個方法GetService,表示獲取指定服務的實例。
而我們將服務的實例化放在了該類的構造函數中,同時給它傳入一個ServiceDescriptor集合對象,這個對象就包裹著需要註入服務的詳細信息。隨後使用指定的方式(在這裡其實又抽象出來了一個配置類來指定實例化服務的方式)來實例化服務。
因此,ServiceCollection提供增刪功能,這是對於ServiceDescriptor來存儲的,ServiceDescriptor則是需要註入的服務的描述信息的抽象。ServiceProvider則是根據傳入的配置類以及服務描述信息集合來實例化指定服務。
整個的設計思路其實就是一個抽象化的過程。這在設計中很有借鑒價值。