最近在研究開源代碼,正好發現Asp.net5的源碼,下載地址:https://github.com/aspnet。
今天主要講的是DependencyInjection這部分,拋磚引玉,供大家參考,也歡迎蒞臨斧正。閑話不多說,下面就代碼進行簡單分析
項目架構如下:

一共包含DependencyInjection、DependencyInjection.Abstractions、DependencyInjection.Autofac、DependencyInjection.Ninject以及DependencyInjection.Tests五個工程。
- DependencyInjection.Abstractions 基礎的接口和類,使用時對外暴露的基本信息。
- DependencyInjection 微軟自己實現的DI接口
- DependencyInjection.Autofac 使用Autofac(該組件不知道是否是開源的)實現的DI
- DependencyInjection.Ninject 使用Ninject(該組件也不知道是否開源)實現的DI
- DependencyInjection.Tests 對於上面四個工程的測試代碼,該部分可以不看,但是對於DI的使用還是有參考價值的。
DependencyInjection.Abstractions
該工程包含基本的接口以及一些基礎的類/枚舉。對於面向接口編程,使用者不需要知道實現的細節,只需要了解相應的接口便可。另外三個工程(DependencyInjection、DependencyInjection.Autofac、DependencyInjection.Ninject)就是對於該工程的相關接口的實現;使用中可以選擇其中一個實現即可,也就是說使用微軟這個DI,DependencyInjection.Abstractions是必須引用的類庫,另外三個工程(如上所指),引入一個即可。
DependencyInjection.Abstractions 這個工程中包含的文件不是很多,下面我就將該工程文件截圖:

該工程中缺少一個關鍵接口——IServiceProvider,該接口位於System下,有如下定義:
public interface IServiceProvider { object GetService(Type serviceType); }
該接口的作用是根據傳入的類型,並把它轉化為相應的實例,該接口是DI的核心,是最終干活的類/接口。
但是該接口的定義存在缺陷,返回值類型是object類型的,用戶使用的時候還需要進行強制類型轉換,所以就對該接口進行了擴展(ServiceProviderExtensions),擴展的定義如下(省略了具體實現):
public static class ServiceProviderExtensions { public static T GetService<T>([NotNull] this IServiceProvider provider); public static object GetRequiredService([NotNull] this IServiceProvider provider, [NotNull] Type serviceType); public static T GetRequiredService<T>([NotNull] this IServiceProvider provider); public static IEnumerable<T> GetRequiredServices<T>([NotNull] this IServiceProvider provider); public static IEnumerable<object> GetRequiredServices([NotNull] this IServiceProvider provider, [NotNull] Type serviceType); }
使用ServiceProvidoer創建出來的實例實際是有相應的生命周期的,框架中使用枚舉ServiceLifetime表示,定義如下:
public enum ServiceLifetime { Singleton,//全局唯一 Scoped,//一定范圍的 Transient//瞬間 }
一共分為三種,三種的時間長短是Transient<Scoped<Singleton。Transient代表僅當前實例(每次都創建一個新的),Scoped代表當前范圍(會在ServiceScope中定義),Singleton代表全家唯一(類似於單例)。
IServiceScopeFactory和IServiceScope,這倆個接口很簡單,故名思義IServiceScopeFactory是Scope的一個工廠類,產生一個ServiceScope對象。IServiceScope對象會生成一個IServiceProvidoer對象,一般來說通過IServiceScope就是枚舉Scoped所代表的范圍。這倆個接口定義如下:
public interface IServiceScopeFactory { IServiceScope CreateScope(); } public interface IServiceScope : IDisposable { IServiceProvider ServiceProvider { get; } }
對於注冊成Scoped范圍的接口/類,可以通過不同的Scope拿到不同的IServiceProvidoer,之后創建不同的范圍的實例,下面我將Tests工程下的一段測試代碼拿出來,略作修改(將var 替換成實際的接口,閱讀方便)
//services.AddScoped<IFakeScopedService, FakeService>(); public void NestedScopedServiceCanBeResolved() { IServiceProvider container = CreateContainer(); IServiceScopeFactory outerScopeFactory = container.GetService<IServiceScopeFactory>(); using (IServiceScope outerScope = outerScopeFactory.CreateScope()) { IServiceScopeFactory innerScopeFactory = outerScope.ServiceProvider.GetService<IServiceScopeFactory>(); using (IServiceScope innerScope = innerScopeFactory.CreateScope()) { IFakeScopedService outerScopedService = outerScope.ServiceProvider.GetService<IFakeScopedService>(); IFakeScopedService innerScopedService = innerScope.ServiceProvider.GetService<IFakeScopedService>(); Assert.NotEqual(outerScopedService, innerScopedService); } } }
上面幾個類的關系大概如下圖所示:

ServiceDescriptor類:該類是一個描述類,描述DI的映射關系。該類的屬性主要有3個(並不恰當),注入的源類,注入的生成類,注入的范圍(ServiceLifetime)。而對於注入的生成類又分為三種:生成類的類型、生成類的實例、生成類的工廠。所以ServiceDescriptor的定義如下所示:
public class ServiceDescriptor { public ServiceLifetime Lifetime { get; } public Type ServiceType { get; } public Type ImplementationType { get; } public object ImplementationInstance { get; } public Func<IServiceProvider, object> ImplementationFactory { get; } }
IServiceCollection接口比較簡單就是 IList<ServiceDescriptor>。ServiceCollectionExtensions是對IServiceCollection接口的擴展方法集合。
這幾個類的關系如下圖所示:

剩余倆個類:ActivatorUtilities、ObjectFactory(其實是個代理/delegate)是用於反射創建實例。
整個工程我對接口、類、代理、枚舉重新划分了下文件夾如下圖所示:

將在下一篇文章中對DependencyInjection.Autofac、DependencyInjection.Ninject進行分析,最后再對微軟自己的DI實現進行分析。
