回顾
通过前两节的学习,我们知道 IServiceCollection 以元数据(ServiceDescriptor)的形式存放着用户注册的服务,它的 IServiceCollection 的拓展方法 BuildServiceProvider 为我们提供一个默认的容器 ServiceProvider,然而创建实例对象的任务并不是由他完成的,具体的是引擎 IServiceProviderEngine(更准确点是抽象类 ServiceProviderEngine) 类型来完成的,可以这么说,整个创建对象的核心功能,都由此抽象类控制完成。具体如下:‘
1、具备(根)节点(ServiceProviderEngineScope)控制对象生命周期
2、使用运行时动态创建对象(CallSiteRuntimeResolver),听起来高级其实就是使用 Activator 这个类的封装和重构创建实例的逻辑
3、存储了创建服务实例的委托(RealizedServices)
4、使用 CallSiteFactory 递归地解析服务实例类型的创建方式(IServiceCallSite)
5、创建实例
IServiceProvider 是如何创建的?
在第一节最后我们当时猜测 IServiceProvider 的生命周期可能是Scoped ,接下来我们验证下 IServiceProvider 的创建过程
IServiceCollection services = new ServiceCollection(); var root = services.BuildServiceProvider(); var service1 = root.GetService(); var service2 = root.GetService (); Console.WriteLine(ReferenceEquals(service1, service2)); Console.WriteLine(ReferenceEquals((root as ServiceProvider)._engine.RootScope, service1));
这里我创建一个默认容器但是没有注册任何服务,然后用容器创建了两个 IServiceProvider,接着我们发现,两个 service 是同一个引用,并且和引擎中的根相同,接下来我们开始 debug
internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory { protected ServiceProviderEngine(IEnumerableserviceDescriptors, IServiceProviderEngineCallback callback) { _createServiceAccessor = CreateServiceAccessor; CallSiteFactory = new CallSiteFactory(serviceDescriptors); CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite()); CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite()); } private Func object> CreateServiceAccessor(Type serviceType) { var callSite = CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain()); if (callSite != null) { _callback?.OnCreate(callSite); return RealizeService(callSite); } return _ => null; } internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); _callback?.OnResolve(serviceType, serviceProviderEngineScope); return realizedService.Invoke(serviceProviderEngineScope); } }
由于第一次创建 IServiceProvider,所以 RealizedServices 中没有该创建该服务的委托,接着调用 CreateServiceAccessor 获取创建 IServiceProvider 的委托,我们发现最后的委托依然是抽象方法 RealizeService 返回的,但是抽象方法需要一个 IServiceCallSite 对象,才能返回创建该 IServiceCallSite(中的实例类型)的委托,有点绕,但是这里说明了创建实例不是一个简单的 Type 就能提供的,因为实例可能存在有参构造函数,如何解析有参构造并且首先创建构造函数中的服务就成了 IServiceCallSite 的核心任务,所以我们可以把它称为创建对象的依据。那我们来看 CallSiteFactory 是如何获取服务的依据的
internal class CallSiteFactory { private readonly List_descriptors; private readonly Dictionary _callSiteCache = new Dictionary (); private readonly Dictionary _descriptorLookup = new Dictionary (); internal IServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { lock (_callSiteCache) { if (_callSiteCache.TryGetValue(serviceType, out var cachedCallSite)) { return cachedCallSite; } } } }
首先从依据缓存(_callSiteCache)获取,很幸运,在 ServiceProviderEngine 的初始化过程中,微软为我们提供了 IServiceProvider 和 IServiceScopeFactory 的创建依据,分别是 ServiceProviderCallSite和 ServiceScopeFactoryCallSite,这里拿到依据接下来就交给 DynamicServiceProviderEngine 处理(RealizeService 是一个抽象方法,调用最远实现)
public class DynamicServiceProviderEngine : CompiledServiceProviderEngine { protected override Funcobject> RealizeService(IServiceCallSite callSite) { var callCount = 0; return scope => { if (Interlocked.Increment(ref callCount) == 2) { Task.Run(() => base.RealizeService(callSite)); } return RuntimeResolver.Resolve(callSite, scope); }; } }
实际创建方法仍然是抽象类提供的,此外如果是第二次根据该依据创建实例,就会被父类 CompiledServiceProviderEngine 将创建创建实例的方法翻译成表达式树在转换为委托存储在 RealizedService 中,此时要注意的是一直是创建委托的过程,并没有真正执行 DynamicServiceProviderEngine 提供的方法,这样一来创建 IServiceProvider 的委托就已经有了,传递一个 ServiceProviderEngineScope 给委托就可以完成实例的创建,我们看具体的创建过程,这个时候又会调到 DynamicServiceProviderEngine 中提供的根据依据创建实例的方法,然后调用 CallSiteRuntimeResolver 的 Resolve 方法
public class CallSiteRuntimeResolver : CallSiteVisitorobject> { public object Resolve(IServiceCallSite callSite, ServiceProviderEngineScope scope) { return VisitCallSite(callSite, scope); } protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, ServiceProviderEngineScope scope) { return scope; } }
调用父类的实现,switch 判断出是一个 ServiceProviderCallSite,接着调用抽象方法 VisitServiceProvider 又跳转到子类中的实现,返回 scope
public abstract class CallSiteVisitor{ protected virtual TResult VisitCallSite(IServiceCallSite callSite, TArgument argument) { switch (callSite) { case FactoryCallSite factoryCallSite: return VisitFactory(factoryCallSite, argument); case IEnumerableCallSite enumerableCallSite: return VisitIEnumerable(enumerableCallSite, argument); case ConstructorCallSite constructorCallSite: return VisitConstructor(constructorCallSite, argument); case TransientCallSite transientCallSite: return VisitTransient(transientCallSite, argument); case SingletonCallSite singletonCallSite: return VisitSingleton(singletonCallSite, argument); case ScopedCallSite scopedCallSite: return VisitScoped(scopedCallSite, argument); case ConstantCallSite constantCallSite: return VisitConstant(constantCallSite, argument); case CreateInstanceCallSite createInstanceCallSite: return VisitCreateInstance(createInstanceCallSite, argument); case ServiceProviderCallSite serviceProviderCallSite: return VisitServiceProvider(serviceProviderCallSite, argument); case ServiceScopeFactoryCallSite scopeFactoryCallSite: return VisitServiceScopeFactory(scopeFactoryCallSite, argument); default: throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported"); } } protected abstract TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument); }
这里我们验证了,通过容器获取 IServiceProvider,得到的始终是该容器的根!类似的,我们还可以通过此方式 debug 一遍发现通过容器获取服务 IServiceScopeFactory,返回的始终是该容器的引擎。
第一个 ITransient 实例是如何创建的?
通过对服务 IServiceProvider 创建过程的了解,我们想必也知道了,创建任何服务最终都会首先找到依据(IServiceCallSite),然后根据依据创建实例
private Funcobject> CreateServiceAccessor(Type serviceType) { var callSite = CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain()); if (callSite != null) { _callback?.OnCreate(callSite); return RealizeService(callSite); } return _ => null; } internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor); _callback?.OnResolve(serviceType, serviceProviderEngineScope); return realizedService.Invoke(serviceProviderEngineScope); }
由于第一次创建 ITransient 服务,依据缓存中并没有创建该服务的依据,我们看在 CreateCallSite 中是如何创建依据的
internal IServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { lock (_callSiteCache) { if (_callSiteCache.TryGetValue(serviceType, out var cachedCallSite)) { return cachedCallSite; } IServiceCallSite callSite; try { callSiteChain.CheckCircularDependency(serviceType); callSite = TryCreateExact(serviceType, callSiteChain) ?? TryCreateOpenGeneric(serviceType, callSiteChain) ?? TryCreateEnumerable(serviceType, callSiteChain); } finally { callSiteChain.Remove(serviceType); } _callSiteCache[serviceType] = callSite; return callSite; } }
创建依据(IServiceCallSite)时会依次尝试用三种方式,他们分别是简单实例、自定义泛型、IEnumerable泛型,其实,我们注册的服务基本上都是通过第一种方式就可以找到依据
private IServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) { if (serviceType == descriptor.ServiceType) { IServiceCallSite callSite; if (descriptor.ImplementationInstance != null) { callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance); } else if (descriptor.ImplementationFactory != null) { callSite = new FactoryCallSite(descriptor.ServiceType, descriptor.ImplementationFactory); } else if (descriptor.ImplementationType != null) { callSite = CreateConstructorCallSite(descriptor.ServiceType, descriptor.ImplementationType, callSiteChain); } else { throw new InvalidOperationException("Invalid service descriptor"); } return ApplyLifetime(callSite, descriptor, descriptor.Lifetime); } return null; }
在多个元数据(ServiceDescriptor)中,通过最后一个注册的元数据来创建依据,因为我们注册的实例方式必然是实例类型、实例对象、实例工厂中的一个,这点从元数据的构造器也可以看出来
public class ServiceDescriptor { public ServiceDescriptor( Type serviceType, Type implementationType, ServiceLifetime lifetime) : this(serviceType, lifetime) { ImplementationType = implementationType; } public ServiceDescriptor( Type serviceType, object instance) : this(serviceType, ServiceLifetime.Singleton) { ImplementationInstance = instance; } public ServiceDescriptor( Type serviceType, Funcobject> factory, ServiceLifetime lifetime) : this(serviceType, lifetime) { ImplementationFactory = factory; } }
现在我们已知注册了服务 ITransient,实例类型为 Transient,却可以这样获取实例
IServiceCollection services = new ServiceCollection(); services.AddTransient(); var serviceProvider = services.BuildServiceProvider(); var transientArray = serviceProvider.GetService >(); Console.WriteLine(transientArray.GetType().FullName);
输出结果为 Microsoft.Extensions.DependencyInjection.ITransient[],这是根据元数据创建依据三种方式(简单实例、自定义泛型、IEnumerable泛型)的第三种,因为在元数据中找不到一个服务类型 IEnumerable
private IServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { //省略了很多代码 return new IEnumerableCallSite(itemType, callSites.ToArray()); } return null; }
那自定义泛型是什么意思呢?其实和 IEnumerableCallSite 类似,只不过在试着使用 IEnumerable 泛型创建依据之前,会使用自定义的泛型
internal IServiceCallSite CreateCallSite(Type serviceType, CallSiteChain callSiteChain) { callSite = TryCreateExact(serviceType, callSiteChain) ?? TryCreateOpenGeneric(serviceType, callSiteChain) ?? TryCreateEnumerable(serviceType, callSiteChain); }
由于在框架内部,微软可以识别 IEnumerable 从而创建一个数组,但是如果是一个为之的泛型呢?比如以下
var instance = serviceProvider.GetService>();
在用此方式创建依据时,微软会检测我们是否注入了 IModelService<> 服务(检测元数据中有没有它),最终的依据是 CreateConstructorCallSite
private IServiceCallSite TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && _descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out var descriptor)) { return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain); } return null; } private IServiceCallSite TryCreateOpenGeneric(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) { if (serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == descriptor.ServiceType) { Debug.Assert(descriptor.ImplementationType != null, "descriptor.ImplementationType != null"); var closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments); var constructorCallSite = CreateConstructorCallSite(serviceType, closedType, callSiteChain); return ApplyLifetime(constructorCallSite, Tuple.Create(descriptor, serviceType), descriptor.Lifetime); } return null; }
从而以下代码得以正常执行
interface ITransient { } class Transient : ITransient { } interface IModelService{ } class ModelService : IModelService { } class Program { static void Main(string[] args) { IServiceCollection services = new ServiceCollection(); services.AddTransient (); services.AddTransient(typeof(IModelService<>), typeof(ModelService<>)); var serviceProvider = services.BuildServiceProvider(); var instance = serviceProvider.GetService >(); } }
instance 的实际类型为 Microsoft.Extensions.DependencyInjection.ModelService`1[[Microsoft.Extensions.DependencyInjection.ITransient, DependencyCore, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
到这里我们回到最初,看最简单的,创建一个基本的 ITransient 服务依据时如何进行的!
private IServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain) { if (serviceType == descriptor.ServiceType) { IServiceCallSite callSite; if (descriptor.ImplementationInstance != null) { callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance); } else if (descriptor.ImplementationFactory != null) { callSite = new FactoryCallSite(descriptor.ServiceType, descriptor.ImplementationFactory); } else if (descriptor.ImplementationType != null) { callSite = CreateConstructorCallSite(descriptor.ServiceType, descriptor.ImplementationType, callSiteChain); } else { throw new InvalidOperationException("Invalid service descriptor"); } return ApplyLifetime(callSite, descriptor, descriptor.Lifetime); } return null; }
由于注册方式的差异,所以会有三种情况,这里我们只看以 services.AddTransient
private IServiceCallSite CreateConstructorCallSite(Type serviceType, Type implementationType, CallSiteChain callSiteChain) { callSiteChain.Add(serviceType, implementationType); var constructors = implementationType.GetTypeInfo().DeclaredConstructors.Where(constructor => constructor.IsPublic).ToArray(); IServiceCallSite[] parameterCallSites = null; if (constructors.Length == 0) {//没有公有构造器 throw new InvalidOperationException(Resources.FormatNoConstructorMatch(implementationType)); } else if (constructors.Length == 1) { var constructor = constructors[0]; var parameters = constructor.GetParameters(); //没有参数 if (parameters.Length == 0) { return new CreateInstanceCallSite(serviceType, implementationType); } //获取每个参数的依据 parameterCallSites = CreateArgumentCallSites( serviceType, implementationType, callSiteChain, parameters, throwIfCallSiteNotFound: true); return new ConstructorCallSite(serviceType, constructor, parameterCallSites); } //处理有多个构造器的情形 //代码省略 }
出现多个构造器的情形是,会遍历每一个构造器,找到的第一个不为 null 的参数依据列表,那么这个构造器就是最终创建该实例的构造器,此外遍历并没有结束,如果该构造器中的参数类型集合不是剩余构造器的参数集合的超集,则会抛出异常,举个例子就能明白,一下情形是不能正常实例化的,抛出异常的时候并没有试图创建 IScoped 和 ISingleton 中的任何一个实例,这点很重要!
interface ITransient { } class Transient : ITransient { public Transient(IFoo foo) { } public Transient(IScoped scoped,ISingleton singleton) { } }
由于我们注册的 Transient 是没有有参构造器的,所以我们拿到的依据时一个 CreateInstanceCallSite 类型,但是在 TryCreateExact 方法的最后并没有直接返回它,而是通过 ApplyLifetime(callSite, descriptor, descriptor.Lifetime) 为其申请了一个生命周期,再做返回。
因为 IServiceCallSite 是创建实例的依据,但是我们发现 CreateInstanceCallSite 并没有和生命周期相关的字段,所以最后返回的常常是一个具有生命周期的依据包裹一个具有创建逻辑(构造器中的服务也)的依据!最后返回的是一个依据是 TransientCallSite
public IServiceCallSite ApplyLifetime(IServiceCallSite serviceCallSite, object cacheKey, ServiceLifetime descriptorLifetime) { if (serviceCallSite is ConstantCallSite) { return serviceCallSite; } switch (descriptorLifetime) { case ServiceLifetime.Transient: return new TransientCallSite(serviceCallSite); case ServiceLifetime.Scoped: return new ScopedCallSite(serviceCallSite, cacheKey); case ServiceLifetime.Singleton: return new SingletonCallSite(serviceCallSite, cacheKey); default: throw new ArgumentOutOfRangeException(nameof(descriptorLifetime)); } }
由于第一次创建(实际运行时不管是第一次还是是第二次)将调用 DynamicServiceProviderEngine 中重写的方法提供根据依据创建实例的委托,拿到这个委托后,首先缓存在 RealizedService 中,然后传递根,执行该委托!随后我们又来到了 CallSiteRuntimeResolver 这个类中,在子类中判断依据类型是 TransientCallSite,然后调用下面的方法,到这里我们发现还没有创建实例,仅仅知道了它的生命周期是 Transient,然后通过 TransientCallSite 内部包裹的具有创建逻辑的 IServiceCallSite,去创建实例,拿到实例后,执行 scope 的的 CaptureDisposable 方法将实例存储到根的释放队列中(随着根的释放被释放)
protected override object VisitTransient(TransientCallSite transientCallSite, ServiceProviderEngineScope scope) { return scope.CaptureDisposable( VisitCallSite(transientCallSite.ServiceCallSite, scope)); }
那实例是如何创建的呢?这里再次调用基类的方法 VisitCallSite 方法判断出依据是一个 CreateInstanceCallSite 类型,然后执行 VisitCreateInstance 方法创建实例
protected override object VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, ServiceProviderEngineScope scope) { try { return Activator.CreateInstance(createInstanceCallSite.ImplementationType); } catch (Exception ex) when (ex.InnerException != null) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); // The above line will always throw, but the compiler requires we throw explicitly. throw; } }
IServiceCallSite 依据一览
public interface IServiceCallSite { Type ServiceType { get; } Type ImplementationType { get; } }
依据的原型很简单,包含了服务类型和实现类型,我们看实现 Ctrl + 12
具有生命周期的 IServiceCallSite 有:
1、TransientCallSite
2、ScopedCallSite
3、SingletonCallSite
提供创建方式的 IServiceCallSite 有:
1、IEnumerableCallSite
2、CreateInstanceCallSite
3、ServiceScopeFactoryCallSite
4、ServiceProviderCallSite
5、ConstructorCallSite
6、ConstantCallSite
7、FactoryCallSite
当然并非所有的服务都具有某种意义上的生命周期,从提供创建方式的依据的3、4条也可以看出来,CallSiteVisitor 是如何利用这些依据创建对象的呢?
抽象工厂+多态创建实例
public abstract class CallSiteVisitor{ protected virtual TResult VisitCallSite(IServiceCallSite callSite, TArgument argument) { switch (callSite) { case FactoryCallSite factoryCallSite: return VisitFactory(factoryCallSite, argument); case IEnumerableCallSite enumerableCallSite: return VisitIEnumerable(enumerableCallSite, argument); case ConstructorCallSite constructorCallSite: return VisitConstructor(constructorCallSite, argument); case TransientCallSite transientCallSite: return VisitTransient(transientCallSite, argument); case SingletonCallSite singletonCallSite: return VisitSingleton(singletonCallSite, argument); case ScopedCallSite scopedCallSite: return VisitScoped(scopedCallSite, argument); case ConstantCallSite constantCallSite: return VisitConstant(constantCallSite, argument); case CreateInstanceCallSite createInstanceCallSite: return VisitCreateInstance(createInstanceCallSite, argument); case ServiceProviderCallSite serviceProviderCallSite: return VisitServiceProvider(serviceProviderCallSite, argument); case ServiceScopeFactoryCallSite scopeFactoryCallSite: return VisitServiceScopeFactory(scopeFactoryCallSite, argument); default: throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported"); } } protected abstract TResult VisitTransient(TransientCallSite transientCallSite, TArgument argument); protected abstract TResult VisitConstructor(ConstructorCallSite constructorCallSite, TArgument argument); protected abstract TResult VisitSingleton(SingletonCallSite singletonCallSite, TArgument argument); protected abstract TResult VisitScoped(ScopedCallSite scopedCallSite, TArgument argument); protected abstract TResult VisitConstant(ConstantCallSite constantCallSite, TArgument argument); protected abstract TResult VisitCreateInstance(CreateInstanceCallSite createInstanceCallSite, TArgument argument); protected abstract TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument); protected abstract TResult VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, TArgument argument); protected abstract TResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, TArgument argument); protected abstract TResult VisitFactory(FactoryCallSite factoryCallSite, TArgument argument); }
CallSiteVisitor 这个抽象类是非常有趣的,它像是一个生产器,接受一个有多态特性的依据(IServiceCallSite)和一个参数 TArgument,创建一个 TResult。在 VisisCallSite 方法中,它更像是一个抽象工厂,但是本身又没有提供真正逻辑,所有获取 TResult 的逻辑都将在子类中得到重写。他有三个子类
1、CallSiteRuntimeResolver,运行时解析器,它根据 IServiceCallSite 以及 ServiceProviderEngineScope,获取实例
2、CallSiteExpressionBuilder,将创建实例的方法转换成表达式树
3、CallSiteValidator,和作用域相关
ServiceProviderEngineScope 是如何结合 ServiceProviderEngine 完成 Scoped 和 Singleton 这两种是生命周期的管理的?
我们看运行时解析器中的两个方法,通过 Scoped、Singleton 注册的服务获得的依据分别是 ScopedCallSite、SingletonCallSite,在抽象类 CallSiteVisitor 的 VisisCallSite 方法中我们可以知道最终会从以 CallSiteRuntimeResolver 中的以下两个方法来创建实例
protected override object VisitSingleton(SingletonCallSite singletonCallSite, ServiceProviderEngineScope scope) { return VisitScoped(singletonCallSite, scope.Engine.Root); } protected override object VisitScoped(ScopedCallSite scopedCallSite, ServiceProviderEngineScope scope) { lock (scope.ResolvedServices) { if (!scope.ResolvedServices.TryGetValue(scopedCallSite.CacheKey, out var resolved)) { resolved = VisitCallSite(scopedCallSite.ServiceCallSite, scope); scope.CaptureDisposable(resolved); scope.ResolvedServices.Add(scopedCallSite.CacheKey, resolved); } return resolved; } }
这里我们发现这两种方式获取的实例都是在 ServiceProviderEngineScope 中取得的,只不过一个 Singleton 是在引擎的根 ServiceProviderEngineScope 获取缓存的实例对象,另一个是在当前根中获取缓存的实例对象!