這個系列已經寫了5篇,鏈接地址如下:
[Asp.net 5] DependencyInjection項目代碼分析
[Asp.net 5] DependencyInjection項目代碼分析2-Autofac
[Asp.net 5] DependencyInjection項目代碼分析3-Ninject
[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(1)
[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(2)
如果想對本篇有個更好的了解,建議需要先看
“[Asp.net 5] DependencyInjection項目代碼分析”
“[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(1)”
“[Asp.net 5] DependencyInjection項目代碼分析4-微軟的實現(2)”。
在之前的“上“、”中“倆篇已經介紹了ServiceTable、IGenericService、IService、IServiceCallSite、ServiceEntry、GenericService、InstanceService、FactoryService、Service等類。本節主要介紹核心的”ServicePRovider“類。
IServiceProvider類
IServiceProvider類是微軟這套DependencyInjection中直接對外的接口。而ServiceProvider是直接實現IServiceProvider并且對外直接提供功能的核心類。
對于ServiceProvider不僅要能夠獲取注入的類,還需要根據不同定義的范圍獲取不同范圍的注入類。對于不同的范圍(Transient、Scoped、Singleton),ServiceProvider需要使用不同的邏輯。我們簡單分析下。
下面是不同Scoped范圍的代碼調用。
public void ScopedServiceCanBeResolved() { IServiceProvider container = CreateContainer(); var scopeFactory = container.GetService<IServiceScopeFactory>(); using (var scope = scopeFactory.CreateScope()) { var containerScopedService = container.GetService<IFakeScopedService>(); var scopedService1 = scope.ServiceProvider.GetService<IFakeScopedService>(); var scopedService2 = scope.ServiceProvider.GetService<IFakeScopedService>(); Assert.NotEqual(containerScopedService, scopedService1); Assert.Equal(scopedService1, scopedService2); } } [Fact] public void NestedScopedServiceCanBeResolved() { IServiceProvider container = CreateContainer(); IServiceScopeFactory outerScopeFactory = container.GetService<IServiceScopeFactory>(); using (var outerScope = outerScopeFactory.CreateScope()) { var innerScopeFactory = outerScope.ServiceProvider.GetService<IServiceScopeFactory>(); using (var innerScope = innerScopeFactory.CreateScope()) { var outerScopedService = outerScope.ServiceProvider.GetService<IFakeScopedService>(); var innerScopedService = innerScope.ServiceProvider.GetService<IFakeScopedService>(); Assert.NotEqual(outerScopedService, innerScopedService); } } }CreateScope
我們可以根據不同Scoped的注入實例,實際上是通過獲取不同的IServiceScope對象的ServiceProvider屬性,之后通過該屬性創建。由于是不同的IServiceScope對象,我們可以大膽的假設IServiceScope對象的ServiceProvider屬性也是不同的IServiceProvider對象。所以每個ServiceProvider對象內部,只需要維護一份注入對象的副本即可;由于IServiceScope對象實現了IDisposable接口(用在using上的對象,都實現了IDisposable接口,當using范圍結束后,會自動調用IDisposable的Dispose方法),但注入的對象緩存在IServiceScope的ServiceProvider屬性對象中,所以我們讓ServiceProvider類也實現IDisposable接口,在IServiceScope的Dispose方法內部調用ServiceProvider類的Dispose方法即可。
通過上面的分析,我們可以大致想象出ServiceProvider類的定義,下面就是ServiceProvider類縮減的源代碼:
internal class ServiceProvider : IServiceProvider, IDisposable { private readonly object _sync = new object(); private readonly ServiceProvider _root; private readonly ServiceTable _table; private readonly Dictionary<IService, object> _resolvedServices = new Dictionary<IService, object>(); private ConcurrentBag<IDisposable> _disposables = new ConcurrentBag<IDisposable>(); public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors) { _root = this; _table = new ServiceTable(serviceDescriptors); _table.Add(typeof(IServiceProvider), new ServiceProviderService()); _table.Add(typeof(IServiceScopeFactory), new ServiceScopeService()); _table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table)); } internal ServiceProvider(ServiceProvider parent) { _root = parent._root; _table = parent._table; } public object GetService(Type serviceType); public void Dispose() { var disposables = Interlocked.Exchange(ref _disposables, null); if (disposables != null) { foreach (var disposable in disposables) { disposable.Dispose(); } } }}
對于ServiceProvider對象共有5個屬性,
ServiceProvider的Root屬性展開
首先我們剛才沒有注意到一個問題,就是ServiceProvider類定義不是public的,而是internal的。來我們回憶下類的定義:
internal class ServiceProvider : IServiceProvider, IDisposable
所以我們在外面是無法調用/構建ServiceProvider的實例的,只能在程序集范圍內實例話。那在哪些地方調用該類的構造函數呢?結果發現倆個構造函數都只被調用過一次。下面將調用的代碼列出:
public static class ServiceCollectionExtensions { public static IServiceProvider BuildServiceProvider(this IServiceCollection services) { return new ServiceProvider(services); } }internal class ServiceScopeFactory : IServiceScopeFactory { private readonly ServiceProvider _provider; public ServiceScopeFactory(ServiceProvider provider) { _provider = provider; } public IServiceScope CreateScope() { return new ServiceScope(new ServiceProvider(_provider)); } }ServiceProvider構造函數
新聞熱點
疑難解答