zoukankan      html  css  js  c++  java
  • .net core 轻量级容器 ServiceProvider 源码分析

    1. 首先看 ServiceCollection 的定义
      //定义
      public class ServiceCollection : IServiceCollection
      {
           private readonly List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>();
      
           ......
      }
      
      //接口定义
      public interface IServiceCollection : IList<ServiceDescriptor>
      {
      }

      由此可见,ServiceCollection 本身是一个 List<ServiceDescriptor> 的集合,下面我们来看一下 ServiceDescriptor 的定义

      public class ServiceDescriptor
      {
          //重要的构造函数
          public ServiceDescriptor(Type serviceType, Type implementationType, ServiceLifetime lifetime)
          {
          }
      
          //重要的属性
          /// <summary>
          /// Service 的生命周期
          /// </summary>
          /// <value></value>
          public ServiceLifetime Lifetime { get; }
      
          /// <summary>
          /// Service 的类型
          /// </summary>
          /// <value></value>
          public Type ServiceType { get; }
      
          /// <summary>
          /// Service 的实现类型
          /// </summary>
          /// <value></value>
          public Type ImplementationType { get; }
      
          /// <summary>
          /// Service 对象
          /// </summary>
          /// <value></value>
          public object ImplementationInstance { get; }
      
          /// <summary>
          /// 创建 Service 对象的工厂
          /// </summary>
          /// <value></value>
          public Func<IServiceProvider, object> ImplementationFactory { get; }
      
          ......
      }

      ServiceDescriptor 保存了 Service 类型和 Service 对象之间的关系以及 Service 的生命周期,下面来看一下 Service 的生命周期

      public enum ServiceLifetime
      {
          /// <summary>
          /// 单例
          /// </summary>
          Singleton,
          /// <summary>
          /// 范围内
          /// </summary>
          /// <remarks>
          /// 在 ASP.NET Core 应用中,每一个请求会创建一个范围
          /// </remarks>
          Scoped,
          /// <summary>
          /// 瞬时
          /// </summary>
          Transient
      }

      再来看一下 IServiceCollection 提供的一些拓展方法

      public static class ServiceCollectionServiceExtensions
      {
          //基本是3中形式,都是简单的封装
          public static IServiceCollection AddSingleton(this IServiceCollection services, ...)
          public static IServiceCollection AddScoped(this IServiceCollection services, ...)
          public static IServiceCollection AddTransient(this IServiceCollection services, ...)
      
          ......
          //最终都会调用同一个方法
          private static IServiceCollection Add(
                  IServiceCollection collection,
                  Type serviceType,
                  Type implementationType,
                  ServiceLifetime lifetime)
              {
                  var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
                  collection.Add(descriptor);
                  return collection;
              }
      }

      这些方法的作用都是为了填充 ServiceCollection 中的 _descriptors 字段,IServiceCollection 有一个特别重要的方法,BuildServiceProvider,创建 ServiceProvider 

      public static class ServiceCollectionContainerBuilderExtensions
      {
          public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
              {
                  if (services == null)
                  {
                      throw new ArgumentNullException(nameof(services));
                  }
      
                  if (options == null)
                  {
                      throw new ArgumentNullException(nameof(options));
                  }
      
                  return new ServiceProvider(services, options);
              }
      }

       

    2. ServiceProvider,Service 的提供者,这是一个非常重要的类,也是容器的核心,主要用来创建 Service 对象的实例
      public sealed class ServiceProvider : IServiceProvider, IDisposable{
        
        //
      ServiceProvider 引擎 private readonly IServiceProviderEngine _engine; //构造函数 internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options) { ...... switch (options.Mode) { case ServiceProviderMode.Default:
      //.net core 默认是 true
      if (RuntimeFeature.IsSupported("IsDynamicCodeCompiled")) { _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); }
      else { // Don't try to compile Expressions/IL if they are going to get interpreted _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); } break; case ServiceProviderMode.Dynamic: _engine = new DynamicServiceProviderEngine(serviceDescriptors, callback); break; case ServiceProviderMode.Runtime: _engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback); break; case ServiceProviderMode.ILEmit: _engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback); break; case ServiceProviderMode.Expressions: _engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback); break; default: throw new NotSupportedException(nameof(options.Mode)); } ...... } //从容器中获取对象 public object GetService(Type serviceType) => _engine.GetService(serviceType); ...... }

      由此可见,ServiceProvider 创建对象的过程由 ServiceProviderEngine 接管,而 Engine 有4种,分别是 DynamicServiceProviderEngine,RuntimeServiceProviderEngine,ILEmitServiceProviderEngine,ExpressionsServiceProviderEngine,下面是他们之间的关系,

    3. 由上图可知,ServiceProvider 的最终的核心实现应该在 ServiceProviderEngine 这个抽象类中,下面我们来看一下这个类,我去掉了一些判断和记录日志的逻辑,让代码看起来更简洁
      internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
      {
          private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor;
      
          protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
          {
              _createServiceAccessor = CreateServiceAccessor;
              Root = new ServiceProviderEngineScope(this);
              RuntimeResolver = new CallSiteRuntimeResolver();
              CallSiteFactory = new CallSiteFactory(serviceDescriptors);
              CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
              CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
              RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
          }
      
      //创建 Service 访问者
      private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType) { var callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain()); if (callSite != null) { //调用子类实现的 获得 Service 对象的委托来创建对象 return RealizeService(callSite); } return _ => null; }
      //调用目标工厂
      internal CallSiteFactory CallSiteFactory { get; } //默认运行时解析器 protected CallSiteRuntimeResolver RuntimeResolver { get; } //根容器 public ServiceProviderEngineScope Root { get; } //获得 Service 对象的委托,由子类实现 protected abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite); //获取 Service 对象 internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); return realizedService.Invoke(serviceProviderEngineScope); } //创建一个范围 public IServiceScope CreateScope() { return new ServiceProviderEngineScope(this); } }

      这个类中有几个特别重要的对象,

      1. RuntimeResolver ,Service 对象的创建就是这个对象完成的,当然不同的子类,有不同的实现,
        internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine
        {
            //该类本身并没有定义 RutimeResolver 而是通过父类 CompiledServiceProviderEngine 的 ResolverBuilder 实现的
        }
        
        internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
        {
            //通过编译条件变量来确定是使用 ILEmit 还是使用 Expression
        #if IL_EMIT
            public ILEmitResolverBuilder ResolverBuilder { get; }
        #else
            public ExpressionResolverBuilder ResolverBuilder { get; }
        #endif
        
            public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
            {
        #if IL_EMIT
                ResolverBuilder = new ILEmitResolverBuilder(RuntimeResolver, this, Root);
        #else
                ResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
        #endif
            }
        
            ......
        }
        
        internal class RuntimeServiceProviderEngine : ServiceProviderEngine
        {
            //该类本身没有对应的 RuntimeResolver,直接使用父类默认的 CallSiteRuntimeResolver
        }
        
        internal class ILEmitServiceProviderEngine : ServiceProviderEngine
        {
            private readonly ILEmitResolverBuilder _expressionResolverBuilder;
            public ILEmitServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
            {
                _expressionResolverBuilder = new ILEmitResolverBuilder(RuntimeResolver, this, Root);
            }
        
            ......
        }
        
        internal class ExpressionsServiceProviderEngine : ServiceProviderEngine
        {
            private readonly ExpressionResolverBuilder _expressionResolverBuilder;
            public ExpressionsServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
            {
                _expressionResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
            }
          
            ......
        }

        所以总结来看,有3个对应的 Resolver 分别是:CallSiteRuntimeResolver,ILEmitResolverBuilder,ExpressionResolverBuilder 这3个类都继承于 CallSiteVisitor<TArgument, TResult> 的泛型类,只是对应的泛型参数不太一样

      2. CallSiteFactory,调用目标工厂,主要用来根据 ServiceDescriptor 的定义创建对应的 ServiceCallSite 对象,然后根据该对象来创建 Service 的实例,这个对象比较复杂,下面来看一些简洁的源码
        internal class CallSiteFactory
        {
            private const int DefaultSlot = 0;
            private readonly List<ServiceDescriptor> _descriptors;
            private readonly Dictionary<Type, ServiceDescriptorCacheItem> _descriptorLookup = new Dictionary<Type, ServiceDescriptorCacheItem>();
        
            public CallSiteFactory(IEnumerable<ServiceDescriptor> descriptors)
            {
                _descriptors = descriptors.ToList();
                Populate();
            }
        
            private void Populate()
            {
                /*
                在实例化 CallSiteFactory 对象时,会将 ServiceDescriptor 对象转换成字典 Dictionary<Type, ServiceDescriptorCacheItem>,
                ServiceDescriptorCacheItem 用来将同一个 ServiceType 的 ServiceDescriptor 聚合在一起,其中 ServiceDescriptorCacheItem 
                的 Last 属性,是取最后一个 ServiceDescriptor,这也就是为什么,我们 Add 同一个类型的多个实例时,获取当前类型的实例时,返回的是最后一个实例的原因
                */
                foreach (var descriptor in _descriptors)
                {
                    var cacheKey = descriptor.ServiceType;
                    _descriptorLookup.TryGetValue(cacheKey, out var cacheItem);
                    _descriptorLookup[cacheKey] = cacheItem.Add(descriptor);
                }
            }
        }
        
        private struct ServiceDescriptorCacheItem
        {
            private List<ServiceDescriptor> _items;
        
            public ServiceDescriptor Last
            {
                get
                {
                    return _items[_items.Count - 1];
                }
            }
        
            public ServiceDescriptorCacheItem Add(ServiceDescriptor descriptor)
            {
                var newCacheItem = new ServiceDescriptorCacheItem();
        
                newCacheItem._item = _item;
                newCacheItem._items = _items ?? new List<ServiceDescriptor>();
                newCacheItem._items.Add(descriptor);
        
                return newCacheItem;
            }
        }

        还有几个比较关键的方法,下面来看一下代码

        /*
        根据 ServiceType 创建 ServiceCallSite, 这个方法类似于一个职责链模式,
        先尝试根据普通类型来创建,然后尝试创建泛型类型,最后尝试创建可枚举类型 
        */
        private ServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
        {
            var callSite = TryCreateExact(serviceType, callSiteChain) ??
                TryCreateOpenGeneric(serviceType, callSiteChain) ??
                TryCreateEnumerable(serviceType, callSiteChain);
            return callSite;
        }
        
        //尝试获取简单类型对象
        private ServiceCallSite TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
        {
            if (_descriptorLookup.TryGetValue(serviceType, out var descriptor))
            {
                /*
                descriptor.Last
                这就是为什么在容器中添加同一个类型的实例多次后,返回的总是最后一个实例
                */
                return TryCreateExact(descriptor.Last, serviceType, callSiteChain, DefaultSlot);
            }
            return null;
        }
        private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) { if (serviceType == descriptor.ServiceType) { if (descriptor.ImplementationInstance != null) { //Add 时,直接指定实例对象时 callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance); } else if (descriptor.ImplementationFactory != null) { //Add 时,指定实例工厂时 callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory); } else if (descriptor.ImplementationType != null) { //Add 时,指定类型时 callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain); } return callSite; } return null; } //尝试获取泛型对象 private ServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == descriptor.ServiceType) { var closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments); return CreateConstructorCallSite(lifetime, serviceType, closedType, callSiteChain); } return null; } //尝试获取枚举类型对象 private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { //获取泛型的第一个参数 var itemType = serviceType.GenericTypeArguments.Single(); var callSites = new List<ServiceCallSite>(); if (!itemType.IsConstructedGenericType && _descriptorLookup.TryGetValue(itemType, out var descriptors)) { /* 循环该 ServiceType 所有的 ServiceDescriptor 这就是为什么在容器中添加同一个类型的实例多次后,通过 IEnumerable<T> 去获取时,返回的是多个实例 */ for (int i = 0; i < descriptors.Count; i++) { var descriptor = descriptors[i]; var callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot); callSites.Add(callSite); } } else { //这里的逻辑代表的是泛型中嵌套泛型的情况,是一个递归调用 } return new IEnumerableCallSite(resultCache, itemType, callSites.ToArray()); } return null; } private ServiceCallSite CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain) { //获取公共的构造函数 var constructors = implementationType.GetTypeInfo() .DeclaredConstructors .Where(constructor => constructor.IsPublic) .ToArray(); ServiceCallSite[] parameterCallSites = null; if (constructors.Length == 0) { //如果没有获取到公共的构造函数会抛出异常 throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType)); } else if (constructors.Length == 1) { //当只有一个构造函数时,优化处理逻辑 return new ConstructorCallSite(...); } //存在多个构造函数时,按照构造函数参数的个数倒序排列 Array.Sort(constructors, (a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length)); //最优的构造函数 ConstructorInfo bestConstructor = null; //最优构造函数的参数类型 HashSet<Type> bestConstructorParameterTypes = null; for (var i = 0; i < constructors.Length; i++) { var parameters = constructors[i].GetParameters(); var currentParameterCallSites = CreateArgumentCallSites(...); /* 默认参数最多的构造函数为最优的构造函数,但是要根据参数类型在容器中是否存在来判断, 如果参数多的构造函数,有个别参数在容器中不存在,那么该构造函数不是最优的 */ if (currentParameterCallSites != null) { if (bestConstructor == null) { bestConstructor = constructors[i]; parameterCallSites = currentParameterCallSites; } else { if (bestConstructorParameterTypes == null) { bestConstructorParameterTypes = new HashSet<Type>(bestConstructor.GetParameters().Select(p => p.ParameterType)); } //如果最优构造函数的参数类型,不是其他构造函数的参数类型的超级,抛出【有歧义】的异常 if (!bestConstructorParameterTypes.IsSupersetOf(parameters.Select(p => p.ParameterType))) { throw new InvalidOperationException(message); } } } } return new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites); }
    4. 由于 ServiceProvider 容器本身只支持构造函数注入,所以我们主要关注每个 Resolver 的 VisitConstructor 方法,

      1. CallSiteRuntimeResolver (.net framework 4.6.2 + 默认使用的方式)

        internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>
        {
            protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
            {
                object[] parameterValues;
                if (constructorCallSite.ParameterCallSites.Length == 0)
                {
                    parameterValues = Array.Empty<object>();
                }
                else
                {
                    //循环获取每个参数类型的实例,如果参数类型还依赖于其它的类型,则会递归获取
                    parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
                    for (var index = 0; index < parameterValues.Length; index++)
                    {
                        parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
                    }
                }
        
                return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
            }
        }
      2. ILEmitResolverBuilder (.net core 默认使用方式)
        /*
        由于 IL 我懂的也不是很多,只是大概知道,需要把参数提前准备好放在堆栈上,然后调用 Newobj 就可以实例化对象,
        源码很长,有兴趣想要研究的小伙伴,可以自行学习
        */
        protected override object VisitConstructor(ConstructorCallSite constructorCallSite, ILEmitResolverBuilderContext argument)
        {
            foreach (var parameterCallSite in constructorCallSite.ParameterCallSites)
            {
                VisitCallSite(parameterCallSite, argument);
            }
            argument.Generator.Emit(OpCodes.Newobj, constructorCallSite.ConstructorInfo);
            return null;
        }
        
        private GeneratedMethod BuildTypeNoCache(ServiceCallSite callSite)
        {
            //动态创建方法
            var dynamicMethod = new DynamicMethod("ResolveService",
                attributes : MethodAttributes.Public | MethodAttributes.Static,
                callingConvention : CallingConventions.Standard,
                returnType : typeof(object),
                parameterTypes : new [] { typeof(ILEmitResolverBuilderRuntimeContext), typeof(ServiceProviderEngineScope) },
                owner : GetType(),
                skipVisibility : true);
        
            var info = ILEmitCallSiteAnalyzer.Instance.CollectGenerationInfo(callSite);
            var ilGenerator = dynamicMethod.GetILGenerator(info.Size);
            //创建方法体
            var runtimeContext = GenerateMethodBody(callSite, ilGenerator);
        
            return new GeneratedMethod()
            {
                Lambda = (Func<ServiceProviderEngineScope, object>) dynamicMethod.CreateDelegate(typeof(Func<ServiceProviderEngineScope, object>), runtimeContext),
                Context = runtimeContext,
                DynamicMethod = dynamicMethod
            };
        }
      3. ExpressionResolverBuilder 可以理解为使用表达式树将 CallSiteRuntimeResolver 的代码翻译了一遍
        internal class ExpressionResolverBuilder : CallSiteVisitor<object, Expression>
        {
            protected override Expression VisitConstructor(ConstructorCallSite callSite, object context)
            {
                var parameters = callSite.ConstructorInfo.GetParameters();
                Expression[] parameterExpressions;
                if (callSite.ParameterCallSites.Length == 0)
                {
                    parameterExpressions = Array.Empty<Expression>();
                }
                else
                {
                    //循环每一个参数,根据参数创建表达式
                    parameterExpressions = new Expression[callSite.ParameterCallSites.Length];
                    for (int i = 0; i < parameterExpressions.Length; i++)
                    {
                        parameterExpressions[i] = Convert(VisitCallSite(callSite.ParameterCallSites[i], context), parameters[i].ParameterType);
                    }
                }
                return Expression.New(callSite.ConstructorInfo, parameterExpressions);
            }
        }
    5. 总结一下
      1. ServiceCollection 只不过是用来定义 Service 的类型和定义以及生命周期
      2. Service 类型的创建是最终是通过不同的 RuntimeResolver 来实现的
      3. 源码中还包含大量对缓存的使用,如果没有缓存,这个容器的效率也就太低了,我在分析源码的时候直接略过了,原因是,我觉得缓存一定是在先实现后的基础上再加的,所以我们研究源码的过程中可以先忽略这些缓存的使用
      4. 关于 Service 的生命周期我没有细讲,单例和瞬时都非常好理解,其实最复杂的就是 Scope,有点绕的地方在于维护 IDisposable 类型的资源的释放,当然这个理解起来也不是很难,有兴趣的小伙伴可以自行研究
      5. 源码分析没有讲最基本的 IOC 概念和容器概念,想要理解这些,前提是要对容器的概念非常了解才行
  • 相关阅读:
    mybatis 错误 Invalid bound statement (not found)
    Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
    bug 记录 Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans
    解决:The Tomcat connector configured to listen on port 8182 failed to start. The port may already be in use or the connector may be misconfigured.
    jquery validate 验证插件 解决多个相同的Name 只验证第一个的方案
    phpStorm+xdebug调试(php7.3)
    小程序视频多个视频播放与暂停
    CSS实现单行、多行文本溢出显示省略号(…)
    Packet for query is too large (4,544,730 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
    idea自动在文件头中添加作者和创建时间
  • 原文地址:https://www.cnblogs.com/qianmingjun/p/11889704.html
Copyright © 2011-2022 走看看