• ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】


    到目前为止,我们定义的ServiceProvider已经实现了基本的服务提供和回收功能,但是依然漏掉了一些必需的细节特性。这些特性包括如何针对IServiceProvider接口提供一个ServiceProvider对象,何创建ServiceScope,以及如何提供一个服务实例的集合。

    一、提供一个ServiceProvider对象

    我们知道当将服务类型指定为IServiceProvider接口并调用ServiceProvider的GetService方法是,ServiceProvider对象本身将会作为服务实例返回,这个特性可以利用一个自定义的Service来实现。如下面的代码片段所示,我们定义的这个ServiceProviderService既是一个Service,又是一个ServiceCallSite。它默认采用生命周期管理模式为Scoped,在Invoke和Build方法中,它直接将当前ServiceProvider作为提供的服务实例。在初始化ServiceTable的时候,我们额外添加一个针对ServiceProviderService的ServideEntry。

       1: internal class ServiceProviderService : IService, IServiceCallSite
       2: {
       3:     public ServiceLifetime Lifetime => ServiceLifetime.Scoped;
       4:     public IService Next { get; set; }
       5:  
       6:     public Expression Build(Expression provider)
       7:     {
       8:         return provider;
       9:     }
      10:  
      11:     public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
      12:     {
      13:         return this;
      14:     }
      15:  
      16:     public object Invoke(ServiceProvider provider)
      17:     {
      18:         return provider;
      19:     }
      20: }
      21:  
      22: internal class ServiceTable
      23: {
      24:     public ServiceTable(IServiceCollection services)
      25:     {
      26:         //解析ServiceCollection并添加相应ServiceEntry
      27:         this.ServieEntries[typeof(IServiceProvider)] = new ServiceEntry(new ServiceProviderService());
      28:     }
      29: }


    二、创建ServiceScope

    创建ServiceScope的目的在于创建作为当前ServiceProvider儿子的另一个ServiceProvider,新创建的ServiceProvider不仅与原来的ServiceProvider具有相同的根,同时共享所有的服务注册信息。利用这个新的ServiceProvider来代替现有的ServiceProvider,其主要的目的还是使我们能够及时地回收提供的服务实例。ServiceScope是通过它的工厂ServiceScopeFactory来创建的,所以先创建了如下一个ServiceScopeFactory类和对应的ServiceScope,它们的定义与我们在前面一节介绍的完全一致。

       1: internal class ServiceScope : IServiceScope
       2: {
       3:     public IServiceProvider ServiceProvider { get; private set; }
       4:  
       5:     public ServiceScope(ServiceProvider serviceProvider)
       6:     {
       7:         this.ServiceProvider = serviceProvider;
       8:     }
       9:  
      10:     public void Dispose()
      11:     {
      12:         (this.ServiceProvider as IDisposable)?.Dispose();
      13:     }
      14: }
      15:  
      16: internal class ServiceScopeFactory : IServiceScopeFactory
      17: {
      18:     public ServiceProvider ServiceProvider { get; private set; }
      19:  
      20:     public ServiceScopeFactory(ServiceProvider serviceProvider)
      21:     {
      22:         this.ServiceProvider = serviceProvider;
      23:     }
      24:  
      25:     public IServiceScope CreateScope()
      26:     {
      27:         return new ServiceScope(this.ServiceProvider);
      28:     }
      29: }
      30:  
      31: internal class ServiceProvider : IServiceProvider, IDisposable
      32: {
      33:     
      34:     public ServiceProvider(ServiceProvider parent)
      35:     {
      36:         this.Root = parent.Root;
      37:         this.ServiceTable = parent.ServiceTable;
      38:     }
      39: }

    为了让ServiceProvider的GetService方法在服务类型指定为IServiceScopeFactory接口的时候能够自动返回上面我们定义的ServiceScopeFactory对象,我们依然和上面一样创建了一个自定义的Service,并将其命名为ServiceScopeFactoryService。与ServiceProviderService一样,ServiceScopeFactoryService同时也是一个ServiceCallSite,在Build和Invoke方法中它会返回一个ServiceScopeFactory对象。为了让这个它能够生效,我们依然在ServiceTable初始化的时自动添加一个相应的ServiceEntry。

       1: internal class ServiceScopeFactoryService : IService, IServiceCallSite
       2: {
       3:     public ServiceLifetime Lifetime=> ServiceLifetime.Scoped;
       4:     public IService Next { get; set; }
       5:  
       6:     public IServiceCallSite CreateCallSite(ServiceProvider provider, ISet<Type> callSiteChain)
       7:     {
       8:         return this;
       9:     }
      10:  
      11:     public Expression Build(Expression provider)
      12:     {
      13:         return Expression.New(typeof(ServiceScopeFactory).GetConstructors().Single(), provider);
      14:     }
      15:  
      16:     public object Invoke(ServiceProvider provider)
      17:     {
      18:         return new ServiceScopeFactory(provider);
      19:     }
      20: }
      21:  
      22: internal class ServiceTable
      23: {
      24:     public ServiceTable(IServiceCollection services)
      25:     {
      26:         //解析ServiceCollection并添加相应ServiceEntry
      27:         this.ServieEntries[typeof(IServiceProvider)] =  new ServiceEntry(new ServiceProviderService());
      28:         this.ServieEntries[typeof(IServiceScopeFactory)] = new ServiceEntry(new ServiceScopeFactoryService());
      29:     }
      30: }


    三、提供一组服务的集合

    到目前为止,我们自定义的ServiceProvider尚不具备原生ServiceProvider的一项特性,那就是当调用GetService方法时将服务类型指定为IEnumerable<T>或者直接调用扩展方法GetServices时,得到的是一个服务实例的集合。这个特性可以通过一个自定义的ServiceCallSite来完成,我们将其命名为EnumerableCallSite。

       1: internal class EnumerableCallSite : IServiceCallSite
       2: {
       3:     public Type ElementType { get; private set; }
       4:     public IServiceCallSite[] ServiceCallSites { get; private set; }
       5:  
       6:     public EnumerableCallSite(Type elementType, IServiceCallSite[] serviceCallSites)
       7:     {
       8:         this.ElementType = elementType;
       9:         this.ServiceCallSites = serviceCallSites;
      10:     }
      11:  
      12:     public Expression Build(Expression provider)
      13:     {
      14:         return Expression.NewArrayInit(this.ElementType, this.ServiceCallSites.Select(
      15:             it => Expression.Convert(it.Build(provider), this.ElementType)));
      16:     }
      17:  
      18:     public object Invoke(ServiceProvider provider)
      19:     {
      20:         var array = Array.CreateInstance(this.ElementType, this.ServiceCallSites.Length);
      21:         for (var index = 0; index < this.ServiceCallSites.Length; index++)
      22:         {
      23:             array.SetValue(this.ServiceCallSites[index].Invoke(provider), index);
      24:         }
      25:         return array;
      26:     }
      27: }

    如上面的代码片段所示,EnumerableCallSite具有两个两个只读属性(ElementType和ServiceCallSites),前者表示返回的服务集合的元素类型,后者则返回一组用于提供集合元素的ServiceCallSite。在Invoke和Build方法中,我们只需要根据元素类型创建一个数组,并利用这组ServiceCallSite创建所有的元素即可。这个EnumerableCallSite最终按照如下的方式应用到ServiceProvider的GetServiceCallSite方法中。

       1: internal class ServiceProvider : IServiceProvider, IDisposable
       2: { 
       3:     public IServiceCallSite GetServiceCallSite(Type serviceType, ISet<Type> callSiteChain)
       4:     {
       5:         try
       6:         {
       7:             if (callSiteChain.Contains(serviceType))
       8:             {
       9:                 throw new InvalidOperationException(string.Format("A circular dependency was detected for the service of type '{0}'",serviceType.FullName);
      10:             }
      11:             callSiteChain.Add(serviceType);
      12:             ServiceEntry serviceEntry;
      13:             if (this.ServiceTable.ServieEntries.TryGetValue(serviceType, out serviceEntry))
      14:             {
      15:                 return serviceEntry.Last.CreateCallSite(this, callSiteChain);
      16:             }
      17:  
      18:             if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition()== typeof(IEnumerable<>))
      19:             {
      20:                 Type elementType = serviceType.GetGenericArguments()[0];
      21:                 IServiceCallSite[] serviceCallSites = this.ServiceTable.ServieEntries.TryGetValue(elementType, out serviceEntry)
      22:                     ? serviceEntry.All.Select(it => it.CreateCallSite(this, callSiteChain)).ToArray()
      23:                     : new IServiceCallSite[0];
      24:                 return new EnumerableCallSite(elementType, serviceCallSites);
      25:             }
      26:  
      27:             return null;
      28:         }
      29:         finally
      30:         {
      31:             callSiteChain.Remove(serviceType);
      32:         }
      33:     }
      34:     //其他成员
      35: }

    ASP.NET Core中的依赖注入(1):控制反转(IoC)
    ASP.NET Core中的依赖注入(2):依赖注入(DI)
    ASP.NET Core中的依赖注入(3):服务注册与提取
    ASP.NET Core中的依赖注入(4):构造函数的选择与生命周期管理
    ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【总体设计】
    ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【解读ServiceCallSite】
    ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】

    作者:蒋金楠
    微信公众账号:大内老A
    微博:www.weibo.com/artech
    如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号)。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
  • 相关阅读:
    [PM2][ERROR] Process XXX not found
    python字符串遍历方式
    测试面试LeetCode系列:一维数组的动态和
    测试面试LeetCode系列:打印特定文本第十行内容
    Python循环数组的方法
    MacOS安装telegraf:Error: Permission denied @ apply2files
    机器数据采集工具:telegraf的介绍安装
    第九章 Nacos Config--服务配置
    2020 史上最全IDEA插件总结
    老哥你能写篇 SpringCloud Alibaba 全家桶吗? 看视频太累 太枯燥了 !
  • 原文地址:https://www.cnblogs.com/linybo/p/10053458.html
Copyright © 2020-2023  润新知