在DI容器中注册类型,DI容器就可以帮我们创建类型的实例;如果注册类型实现了IAsyncDisposable
或者IDisposable
接口,对象销毁时DI容器还会帮我们调用DisposeAsync
或Dispose
方法。这是如何实现的呢?一起来看看吧。本文是基于Dependency Injection 8.0
编写。如果已熟练使用,可以直接从第三节开始观看。
功能演示
说明:对象的销毁由GC管理,这里的"销毁"是指调用Dispose
方法。
先介绍一下DI容器中类的三种生命周期:Singleton
(单例)、Scoped
(在每个ServiceProviderEngineScope
中只创建一次,可以理解为局部单例)、Transient
(每次都创建新对象)。
先定义三个代表生命周期的接口ISingletonService
、IScopedService
和ITransientService
;分别在实现类中打印创建信息和Dispose信息。并且在打印信息里添加了HashCode,可以观察是哪个对象被创建和"销毁"。代码在每个Scope中对每个不同生命周期的类创建2个对象,共12次调用,来看看实际上一共创建了几个对象。
csharp
public interface ISingletonService { }
public interface IScopedService{ }
public interface ITransientService { }
public class SingletonService : ISingletonService, IDisposable
{
public SingletonService()
{
Console.WriteLine($"{this.GetType()} 被创建了 - {this.GetHashCode()}...");
}
public void Dispose()
{
Console.WriteLine($"{this.GetType()} 被销毁了- {this.GetHashCode()}...");
}
}
可以看到,Singleton
对象创建了1个,Scoped
对象创建了2个(因为有两个ServiceProviderEngineScope
),Transient
对象每次调用都会创建新的对象,共4个。
Dispose
方法调用顺序是,先创建的最后调用。
ASP.NET CORE中Scope
在ASP.NET CORE中每次请求会创建一个Scope,通过HttpContext.RequestServices
可以获取这个Scope对象,所以生命周期为Scoped
的类在一次请求中只会创建一次,局部单例。
csharp
// HttpContext.RequestServices
public override IServiceProvider RequestServices
{
get { return ServiceProvidersFeature.RequestServices; }
set { ServiceProvidersFeature.RequestServices = value; }
}
public class RequestServicesFeature
{
public IServiceProvider RequestServices
{
get
{
if (!_requestServicesSet && _scopeFactory != null)
{
_context.Response.RegisterForDisposeAsync(this);
//每次请求创建一个Scope
_scope = _scopeFactory.CreateScope();
_requestServices = _scope.ServiceProvider;
_requestServicesSet = true;
}
return _requestServices!;
}
set
{
_requestServices = value;
_requestServicesSet = true;
}
}
}
深入理解
要理解对象的创建和"销毁",ServiceProvider
类是关键。
ServiceProvider
创建和"销毁"对象主要是通过它的两个成员来完成的;分别是ServiceProviderEngine _engine
和ServiceProviderEngineScope Root
ServiceProviderEngine
这是一个抽象类,只有一个方法RealizeService
,该方法返回一个创建实例的委托。该类不直接创建对象,而是提供一个创建对象的委托!ServiceProviderEngineScope
又可以分两类,根scope
和子scope
,它们的主要功能是:
捕获创建的对象存入List<object>? _disposables
中,用于调用Dispose
方法。
ServiceProviderEngine
通过类型信息创建实例主要有三种办法 1.反射,2.表达式树,3.Emit。这些功能实现在ServiceProviderEngine
的子类中,继承关系如下:
ServiceProviderEngine
RuntimeServiceProviderEngine
反射ExpressionsServiceProviderEngine
表达式树ILEmitServiceProviderEngine
EmitCompiledServiceProviderEngine
表达式树和Emit的组合DynamicServiceProviderEngine
默认用的这个Engine,实现方式有点难理解
下面看一下这些类的实现
csharp
internal sealed class ExpressionsServiceProviderEngine : ServiceProviderEngine
{
//使用这个类构建表达式树
private readonly ExpressionResolverBuilder _expressionResolverBuilder;
//返回一个创建对象的委托!
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
return _expressionResolverBuilder.Build(callSite);
}
}
internal sealed class ILEmitServiceProviderEngine : ServiceProviderEngine
{
//使用这个类构建emit
private readonly ILEmitResolverBuilder _expressionResolverBuilder;
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{
return _expressionResolverBuilder.Build(callSite);
}
}
internal sealed class RuntimeServiceProviderEngine : ServiceProviderEngine
{ // 反射
public static RuntimeServiceProviderEngine Instance { get; } = new RuntimeServiceProviderEngine();
//使用反射相关方法在CallSiteRuntimeResolver中
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{
return scope => CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
}
}
internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
{
//通过以下方式选择默认创建实例的方式
#if IL_EMIT
public ILEmitResolverBuilder ResolverBuilder { get; } //emit构建
#else
public ExpressionResolverBuilder ResolverBuilder { get; } //表达式树构建
#endif
public CompiledServiceProviderEngine(ServiceProvider provider)
{
ResolverBuilder = new(provider);
}
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite);
}
默认是使用emit
的方式创建对象,通过以下方法可以验证默认使用的引擎和创建实例的方式
csharp
static void EngineInfo(ServiceProvider provider)
{
var p = Expression.Parameter(typeof(ServiceProvider));
//相当于 provider._engine
var lambda = Expression.Lambda<Func<ServiceProvider, object>>(Expression.Field(p, "_engine"), p);
var engine = lambda.Compile()(provider);
var baseType = engine.GetType().BaseType!;
// 相当于(provider._engine as CompiledServiceProviderEngine).ResolverBuilder
var lambda2 = Expression.Lambda<Func<ServiceProvider, object>>(
Expression.Property(Expression.Convert(Expression.Field(p, "_engine"), baseType), "ResolverBuilder"), p);
var builder = lambda2.Compile()(provider);
Console.WriteLine(engine.GetType());
Console.WriteLine(builder.GetType());
//输出信息:
//Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine
//Microsoft.Extensions.DependencyInjection.ServiceLookup.ILEmitResolverBuilder
}
从上面输出可以看到DynamicServiceProviderEngine
是默认的Engine,并且它的父类CompiledServiceProviderEngine
是使用的ILEmitResolverBuilder
。
下面来介绍DynamicServiceProviderEngine
,这段代码三年前看不懂,我三年后还是不太懂,实现方式有点难以理解,有大佬懂的可以解答下。
首先,Singleton
对象是不会调用这个方法的,只有生命周期是Scoped
和Transient
才会调用这个方法。通过调用RealizeService
获取一个创建对象的委托;对于每一个服务标识
,在调用2次后,替换为用emit的方式去创建实例的委托 (如果不理解服务标识
,看我的这篇文章),并且,还是用线程池实现的,对于Web开发,而CPU绑定的异步不推荐使用线程池。
前几次调用,反射性能应该是优于emit和表达式树,因为后两者有一个构建委托的过程。但是,使用线程池的影响应该远大于前者吧。一开始就直接使用emit创建对象不应该优于使用线程池?上百个类使用线程池,会导致网站启动时很卡。当然,也就启动后一小段时间卡。
csharp
internal sealed class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{
int callCount = 0;
return scope =>
{
// Resolve the result before we increment the call count, this ensures that singletons
// won't cause any side effects during the compilation of the resolve function.
var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
if (Interlocked.Increment(ref callCount) == 2)
{
//不捕获ExecutionContext,AsyncLocal失效。
_ = ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
_serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));
},
null);
}
return result;
};
}
}
获取创建对象的委托时,需要传入参数ServiceCallSite
,callSite对象有类型的创建信息,指明如何创建这个类型的实例,比如通过构造函数、工厂、创建数组(IEnumerable<>服务)、常量等创建实例。并且在后面调用创建对象的委托时,如果需要缓存,会把创建出来的对象缓存到callSite对象中。
ServiceProviderEngineScope
下面再来介绍下ServiceProviderEngineScope
,主要成员及相关介绍在下面代码中。
如何创建ServiceProviderEngineScope
对象呢?通过services.CreateScope()
就是创建一个scope
对象。创建scope
对象时,会传递ServiceProvider
并保存到RootProvider
属性中。而每个scope
对象又有一个名字为ServiceProvider
的属性,它的值是this
;所以scope.ServiceProvider == scope
。
我们发现这个对象也有GetService
方法,发现它只是转发了一下,其实还是调用ServiceProvider
的GetService
获取对象。这个方法还把当前scope
作为参数传递过去了,表示创建出来的对象由当前scope
对象管理。
我们通过scope.ServiceProvider.GetService<ISingletonService>()
获取对象和services.GetService<ISingletonService>()
基本一样,只是传递的scope
不同,前者是传递自己,后者是传递ServiceProvider
对象中的scope
对象(也就是Root
属性)。
再次说明:scope.ServiceProvider
是返回自己,scope.RootProvider
才是真正的ServiceProvider
对象
csharp
internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IKeyedServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
//缓存创建出来的对象,只会缓存"非根Scope"创建的且生命周期为"Scoped"的实例
internal Dictionary<ServiceCacheKey, object?> ResolvedServices { get; }
// 存放捕获的 disposables 对象
private List<object>? _disposables;
//是否为根Scope
public bool IsRootScope { get; }
//这里有点绕,ServiceProvider属性返回的是自己。每个子Scope就是 engineScope
public IServiceProvider ServiceProvider => this;
//RootProvider属性是保存的ServiceProvider对象
internal ServiceProvider RootProvider { get; }
//所有创建Scope的方法都是调用 ServiceProvider的CreateScope方法
public IServiceScope CreateScope() => RootProvider.CreateScope();
//唯一构造函数
public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope)
{
ResolvedServices = new Dictionary<ServiceCacheKey, object?>();
RootProvider = provider; //保存ServiceProvider对象
IsRootScope = isRootScope;//只有ServiceProvider对象中的scope对象的这个值是true,其它都是false
}
public object? GetService(Type serviceType)
{
//每个子scope还是调用RootProvider创建服务,只是由子scope捕获对象用于释放Dispose
return RootProvider.GetService(ServiceIdentifier.FromServiceType(serviceType), this);
}
}
在ServiceProvider
的构造函数中,注册了IServiceProvider
和IServiceScopeFactory
服务。两者都是返回一个ServiceProviderEngineScope
对象,前者是返回当前scope
对象,后者是返回单例根scope
对象(Root
属性)。这是理解创建scope对象流程的前提。
调用services.CreateScope()
创建scope对象流程:
- 1.调用
ServiceProvider
的CreateScope方法。services.CreateScope()
- 2.CreateScope方法就是获取
根scope
并调用它自己的CreateScope方法。provider.GetRequiredService<IServiceScopeFactory>().CreateScope()
- 3.而
根scope
的CreateScope方法是调用ServiceProvider
的CreateScope方法。RootProvider.CreateScope()
- 4.在
ServiceProvider
的CreateScope方法中就是new一个对象。new ServiceProviderEngineScope(this, isRootScope: false)
兜兜转转,services.CreateScope()
最终是调用自己内部方法CreateScope
。代码和注释已贴出,结合上下两段代码看。
csharp
//这是在ServiceProvider的构造函数中注册的服务
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceProvider)), new ServiceProviderCallSite());
CallSiteFactory.Add(ServiceIdentifier.FromServiceType(typeof(IServiceScopeFactory)), new ConstantCallSite(typeof(IServiceScopeFactory), Root));
//我们创建Scope是调用的这个扩展方法,结合上面代码,你会发现CreateScope其实是调用的自己的同名方法
public static IServiceScope CreateScope(this IServiceProvider provider)
{
return provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
}
//这里是ServiceProvider的CreateScope方法,它"internal"修饰的,但最终调用的这里
internal IServiceScope CreateScope()
{
// 创建Scope最终是调用的这里,ServiceProvider会保存在每个Scope里,每个Scope都是同一个ServiceProvider
return new ServiceProviderEngineScope(this, isRootScope: false);
}
根scope和子scope
根scope
和子scope
通过IsRootScope
属性区分,保存在ServiceProvider
中的Root
属性就是一个根scope
,其生命周期是全局的,程序停止才会调用Dispose
方法。ASP.NET CORE中每次请求创建的scope
就是一个子scope
。通过两个例子加深印象:
csharp
static void EngineScopeTest()
{
using var services = new ServiceCollection().BuildServiceProvider();
using var scope1 = services.CreateScope();
using var scope2 = scope1.ServiceProvider.CreateScope();
//返回当前scope
var rootScope = services.GetService<IServiceProvider>();
//返回根scope
var rootScope2 = services.GetService<IServiceScopeFactory>();
var currentScope = scope1.ServiceProvider.GetService<IServiceProvider>();
var rootScope3 = scope1.ServiceProvider.GetService<IServiceScopeFactory>();
var currentScope2 = scope2.ServiceProvider.GetService<IServiceProvider>();
var rootScope4 = scope2.ServiceProvider.GetService<IServiceScopeFactory>();
// 获取根scope
var root = GetRoot(services);
//运行代码输出4个 True
Console.WriteLine(rootScope == root && rootScope == (root as IServiceScope)!.ServiceProvider);
Console.WriteLine(rootScope == rootScope3 && rootScope == rootScope4);
Console.WriteLine(currentScope == scope1 && currentScope == scope1.ServiceProvider);
Console.WriteLine(currentScope2 == scope2 && currentScope2 == scope2.ServiceProvider);
}
static object GetRoot(ServiceProvider provider)
{ //通过表达式树获取根scope
var p = Expression.Parameter(typeof(ServiceProvider));
//相当于 provider.Root
var lambda = Expression.Lambda<Func<ServiceProvider, object>>(Expression.Property(p, "Root"), p);
return lambda.Compile()(provider);
}
调用GetService<IServiceProvider>()
返回的是当前scope
,调用GetService<IServiceScopeFactory>()
返回的是根scope
。就算通过子scope方法scope1.ServiceProvider.CreateScope()
创建scope,最终还是调用new ServiceProviderEngineScope(this, isRootScope: false)
创建scope,并且子scope
之间没有层级关系,每个子scope
都保存了同一份ServiceProvider
对象。
再通过以下例子验证一下,子scope是否真的保存了ServiceProvider
对象
csharp
static void EngineScopeWhitServiceProviderTest()
{
using var services = new ServiceCollection().BuildServiceProvider();
using var scope1 = services.CreateScope()!;
using var scope2 = scope1.ServiceProvider.CreateScope()!;
var rootScope = services.GetService<IServiceProvider>();
var currentScope = scope1.ServiceProvider.GetService<IServiceProvider>();
var currentScope2 = scope2.ServiceProvider.GetService<IServiceProvider>();
var provider = GetRootProvider(scope1);//获取子scope保存的ServiceProvider
var provider2 = GetRootProvider(scope2);//获取子scope保存的ServiceProvider
//获取根scope的ServiceProvider
var root = (IServiceScope)GetRoot(services);
var provider3 = GetRootProvider(root);
Console.WriteLine(services == provider && services == provider2 && services == provider3);
Console.WriteLine(services != rootScope && services != currentScope && services != root.ServiceProvider);
}
static object GetRootProvider(IServiceScope scope)
{ //通过表达式树获取RootProvider
var p = Expression.Parameter(typeof(IServiceScope));
//相当于 scope.RootProvider
var lambda = Expression.Lambda<Func<IServiceScope, object>>(
Expression.Property(Expression.Convert(p, scope.GetType()), "RootProvider"), p);
return lambda.Compile()(scope);
}
验证没问题。根scope
和子scope
的几个特点:
- 都会捕获需要释放
Dispose
的对象 - 所有
Singleton
对象的"销毁"由根scope
管理 - 对于
Scoped
和Transient
的对象,谁关联谁管理(创建对象时需要传入一个关联scope对象)- 注意:对于
Scoped
和Transient
的对象被ServiceProvider
创建时,它们的生命周期就变成了Singleton
,它们的Dispose
方法往往需要等程序停止时才会调用。虽然可以在创建容器时设置参数ValidateScopes
开启校验,但只会校验Scoped
对象,它只会禁止ServiceProvider
中创建Scoped对象和Singleton
对象中注入Scoped
对象,对于Transient
对象不会校验,所以Transient
对象的Dispose
方法要等程序停止时才会调用。
- 注意:对于
子scope
会缓存生命周期为"Scoped"的实例,并保存到ResolvedServices
属性中。- 虽然后面会把创建对象的委托替换成了
Emit
的形式,但是生命周期为"Scoped"的实例已经保存到ResolvedServices
属性中,所以后面创建的"Scoped"的实例还是同一个。
- 虽然后面会把创建对象的委托替换成了
- 对于
根scope
关联的Singleton
和Scoped
对象,创建出来后都会缓存,只是保存在不同地方(创建对象的委托中或ServiceCallSite
中)。
问:子scope
创建的Singleton
对象是由根scope
管理的,那子scope
是怎样获取根scope
对象的呢?
答:前面讲过,子scope
会保存ServiceProvider
对象,访问它的Root
属性就可以得到根scope
。像这样scope1.RootProvider.Root
。这两个成员的修饰符都是internal
,我们要想访问,可以参考前面的代码GetRootProvider
和GetRoot
Dispose
对象被DI容器创建出来,如果有实现Dispose
接口,就会被ServiceProviderEngineScope
捕获并放入对象List<object>? _disposables
中,并在DI容器本身被调用Dispose
方法时,会逆序调用_disposables
中每个对象的Dispose
方法( for (int i = _disposables.Count - 1; i >= 0; i--)
),也就是调用scope
的Dispose
方法就会调用它捕获对象的Dispose
方法。
scope
的Dispose
方法调用的时机:
- 对于
根scope
,也就是ServiceProvider
的Root属性,当ServiceProvider
的Dispose
方法被调用时,会调用Root.Dispose()
- 对于
子scope
需要自己手动调用Dispose
方法或者用using
。
通过一段代码来验证一下scope
对象是否真的捕获了对象:
csharp
static void DisposeTest()
{
using var services = new ServiceCollection()
.AddSingleton<ISingletonService, SingletonService2>()
.AddScoped<IScopedService, ScopedService2>()
.AddTransient<ITransientService, TransientService2>()
.BuildServiceProvider();
var singleton1 = services.GetService<ISingletonService>();
var scoped1 = services.GetService<IScopedService>();
var transient1 = services.GetService<ITransientService>();
//获取被捕获的对象
var rootDisposables = GetRootDisposables(services);
Console.WriteLine(rootDisposables.Any(o => o == singleton1)
&& rootDisposables.Any(o => o == scoped1)
&& rootDisposables.Any(o => o == transient1)
&& rootDisposables.Count == 3);
using (var scope1 = services.CreateScope())
{
var singleton2 = scope1.ServiceProvider.GetService<ISingletonService>();
var scoped2 = scope1.ServiceProvider.GetService<IScopedService>();
var transient2 = scope1.ServiceProvider.GetService<ITransientService>();
var singleton3 = scope1.ServiceProvider.GetService<ISingletonService>();
var scoped3 = scope1.ServiceProvider.GetService<IScopedService>();
var transient3 = scope1.ServiceProvider.GetService<ITransientService>();
//获取被捕获的对象
var scopeDisposables = GetScopeDisposables(scope1.ServiceProvider);
//Singleton保存在Root Scope中
Console.WriteLine(scopeDisposables.Any(o => o == singleton2) == false
&& scopeDisposables.Any(o => o == singleton3) == false
&& scopeDisposables.Count == 3);//2个Transient对象,1个Scope对象
Console.WriteLine(scopeDisposables.Any(o => o == scoped2)
&& scopeDisposables.Any(o => o == transient2)
&& scopeDisposables.Any(o => o == scoped3)
&& scopeDisposables.Any(o => o == transient3));
}
}
static List<object> GetRootDisposables(ServiceProvider provider)
{
var providerParam = Expression.Parameter(typeof(ServiceProvider));
// provider.Root
var engineParam = Expression.Property(providerParam, "Root");
// provider.Root._disposables;
var dispoParam = Expression.Field(engineParam, "_disposables");
var lambda = Expression.Lambda<Func<ServiceProvider, List<object>>>(dispoParam, providerParam);
return lambda.Compile()(provider);
}
static List<object> GetScopeDisposables(IServiceProvider provider)
{
//这个provider就是ServiceProviderEngineScope
var providerParam = Expression.Parameter(typeof(IServiceProvider));
// provider as ServiceProviderEngineScope
var engineParam = Expression.Convert(providerParam, provider.GetType());
// (provider as ServiceProviderEngineScope)._disposables;
var dispoParam = Expression.Field(engineParam, "_disposables");
var lambda = Expression.Lambda<Func<IServiceProvider, List<object>>>(dispoParam, providerParam);
return lambda.Compile()(provider);
}
输出3个True,没问题。
ServiceProvider
最后再介绍一下,ServiceProvider
是如何利用ServiceProviderEngineScope
和ServiceProviderEngine
创建和管理对象的。类ServiceIdentifier是DI8.0的新功能
csharp
private sealed class ServiceAccessor
{
//类型的创建信息和缓存
public ServiceCallSite? CallSite { get; set; }
//来自ServiceProviderEngine的RealizeService方法
public Func<ServiceProviderEngineScope, object?>? RealizedService { get; set; }
}
//注意,RealizeService方法的参数和返回值就是ServiceAccessor类的成员
internal sealed class ILEmitServiceProviderEngine : ServiceProviderEngine
{
public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite)
{
//...
}
}
public sealed class ServiceProvider : IServiceProvider, IKeyedServiceProvider, IDisposable, IAsyncDisposable
{
//伪代码,但最终是new DynamicServiceProviderEngine
internal ServiceProviderEngine _engine = new DynamicServiceProviderEngine(this);
//根scope 它的IsRootScope属性为true
internal ServiceProviderEngineScope Root { get; }
//我们获取服务最终都是调用这里
internal object? GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
{
//_serviceAccessors是一个字典,可以理解为每一个服务标识对应一个创建对象的创建对象的委托
ServiceAccessor serviceAccessor = _serviceAccessors.GetOrAdd(serviceIdentifier, CreateServiceAccessor);
//调用 委托 获取对象
object? result = serviceAccessor.RealizedService?.Invoke(serviceProviderEngineScope);
return result;
}
private ServiceAccessor CreateServiceAccessor(ServiceIdentifier serviceIdentifier)
{
//GetCallSite方法获取类型的创建信息,指明如何创建这个类型的实例,比如通过构造函数、工厂、创建数组(IEnumerable<>服务)、常量等创建实例
ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceIdentifier, new CallSiteChain());
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
{
//Singleton对象,通过反射创建一次
object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
//Resolve方法里,在对象创建出来后会保存到callSite里面,如果实现dispose接口还会被Root捕获
return new ServiceAccessor { CallSite = callSite, RealizedService = scope => value };
}
//调用 ServiceProviderEngine 获取一个 创建对象的委托
Func<ServiceProviderEngineScope, object?> realizedService = _engine.RealizeService(callSite);
return new ServiceAccessor { CallSite = callSite, RealizedService = realizedService };
}
}
代码只保留了核心逻辑。创建对象时,所有的GetService
方法最终都是调用这个方法GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope)
。该方法接收一个"服务标识"和一个"ServiceProviderEngineScope"对象,如果是通过services.GetService
调用,传递的就是根scope
;如果是通过scope1.ServiceProvider.GetService
调用,传递的就是当前子scope
对象。
GetService
方法先通过CreateServiceAccessor
获取"服务标识"相关信息(ServiceCallSite
)和创建对象的委托。ServiceCallSite
前面有介绍。Singleton
对象不会通过ServiceProviderEngine
的RealizeService
方法获取创建对象的委托,而是直接通过反射创建对象并缓存起来。Scoped
和Transient
对象通过 _engine.RealizeService(callSite)
获取创建对象的委托。最后就是调用委托获取对象。
总结
.NET依赖注入中获取对象就是通过GetService方法,方法内容主要就两步:
- 1.获取创建对象的委托(通过
ServiceProviderEngine
) - 2.调用委托创建对象
如果创建出来的对象实现了IAsyncDisposable
或者IDisposable
接口,创建出来的对象会被ServiceProviderEngineScope
捕获用于调用Dispose
方法。
如有疑问,欢迎评论交流。如有错误,欢迎批评指出。
写文章是真累!以后尽量多写文章,这样也能放在简历上了。
最后,我好像失业了,从上个月15号投简历到现在已经一个月了,就几个面试。磨练心态中......有没有大佬招人,技术牛逼的公司,我少拿工资也心甘情愿。