这个系列已经写了5篇,链接地址如下:
如果想对本篇有个更好的了解,建议需要先看
“[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); } } }
我们可以根据不同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)); } }
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; }
ServiceProvider的属性我们已经讲完,那我们继续看下构造函数内其他的东西(上面的代码就是其构造函数)。我们发现ServiceTable内额外添加IServiceProvider、IServiceScopeFactory、IEnumerable<>的注入。
internal class ServiceProviderService : IService, IServiceCallSite { public IService Next { get; set; } public ServiceLifetime Lifetime { get { return ServiceLifetime.Scoped; } } public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain) { return this; } public object Invoke(ServiceProvider provider) { return provider; } public Expression Build(Expression provider) { return provider; } }
internal class ServiceScopeService : IService, IServiceCallSite { public IService Next { get; set; } public ServiceLifetime Lifetime { get { return ServiceLifetime.Scoped; } } public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain) { return this; } public object Invoke(ServiceProvider provider) { return new ServiceScopeFactory(provider); } public Expression Build(Expression provider) { return Expression.New( typeof(ServiceScopeFactory).GetTypeInfo() .DeclaredConstructors .Single(), provider); } } internal class ServiceScopeFactory : IServiceScopeFactory { private readonly ServiceProvider _provider; public ServiceScopeFactory(ServiceProvider provider) { _provider = provider; } public IServiceScope CreateScope() { return new ServiceScope(new ServiceProvider(_provider)); } } internal class ServiceScope : IServiceScope { private readonly ServiceProvider _scopedProvider; public ServiceScope(ServiceProvider scopedProvider) { _scopedProvider = scopedProvider; } public IServiceProvider ServiceProvider { get { return _scopedProvider; } } public void Dispose() { _scopedProvider.Dispose(); } }