zoukankan      html  css  js  c++  java
  • [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实现进行分析。

  • 相关阅读:
    React项目(垃圾分类后台管理)
    React 学习笔记
    xml学习
    .NET Core部署Windows服务
    .NET 生成PDF流
    无线数传电台是什么
    电流电压采集模块如何进行数据传输的
    Spring5快乐教程(十)AspectJ注解实现AOP
    Spring5快乐教程(九)注解编程详解
    Spring5快乐教程(八)注解编程详解
  • 原文地址:https://www.cnblogs.com/watermoon2/p/4511269.html
Copyright © 2011-2022 走看看