zoukankan      html  css  js  c++  java
  • 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
    如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号)。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
  • 相关阅读:
    1012 The Best Rank (25 分)(排序)
    1011. World Cup Betting (20)(查找元素)
    1009 Product of Polynomials (25 分)(模拟)
    1008 Elevator (20 分)(数学问题)
    1006 Sign In and Sign Out (25 分)(查找元素)
    1005 Spell It Right (20 分)(字符串处理)
    Kafka Connect 出现ERROR Failed to flush WorkerSourceTask{id=local-file-source-0}, timed out while wait
    flume、kafka、avro组成的消息系统
    Java23种设计模式总结【转载】
    Java编程 思维导图
  • 原文地址:https://www.cnblogs.com/linybo/p/10053458.html
Copyright © 2011-2022 走看看