[Asp.net 5] DependencyInjection項目代碼分析


最近在研究開源代碼,正好發現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實現進行分析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM