();
}
return person;
}
源码探究
通过上面的示例,我们可以看到其实关于IServiceScope
的操作部分就是三个核心。
- 通过
CreateScope()
或CreateAsyncScope()
方法创建服务作用域。
- 使用
GetService
相关的方法创建需要的对象实例。
- 用完了作用域之后通过使用
Dispose()
或者DisposeAsync()
方法(using的方式同理)释放作用域。
先说AsyncServiceScope
为了怕大家心里有疑虑,因为使用CreateScope()
方法创建出来的是IServiceScope
实例,使用CreateAsyncScope
方法创建的是AsyncServiceScope
实例。咱们这里先来说一下AsyncServiceScope
和IServiceScope
的关系,看了之后大家就不用惦记它了,先来看一下CreateAsyncScope()
方法的定义[点击查看源码??]
public static AsyncServiceScope CreateAsyncScope(this IServiceProvider provider)
{
return new AsyncServiceScope(provider.CreateScope());
}
方法就是返回AsyncServiceScope
实例,接下来来看一下这个类的定义[点击查看源码??]
public readonly struct AsyncServiceScope : IServiceScope, IAsyncDisposable
{
private readonly IServiceScope _serviceScope;
public AsyncServiceScope(IServiceScope serviceScope)
{
//AsyncServiceScope也是IServiceScope实例构建起来的
_serviceScope = serviceScope ?? throw new ArgumentNullException(nameof(serviceScope));
}
//ServiceProvider也是直接在IServiceScope实例中直接获取的
public IServiceProvider ServiceProvider => _serviceScope.ServiceProvider;
//同步释放
public void Dispose()
{
_serviceScope.Dispose();
}
//异步释放
public ValueTask DisposeAsync()
{
//因为IAsyncDisposable的ServiceProvider能继续创建作用域
//使用CreateScope或CreateAsyncScope方法
if (_serviceScope is IAsyncDisposable ad)
{
return ad.DisposeAsync();
}
_serviceScope.Dispose();
return default;
}
}
通过源码我们可以看到AsyncServiceScope
本身是包装了IServiceScope
实例,它本身也是实现了IServiceScope
接口并且同时IAsyncDisposable
接口以便可以异步调用释放。相信大家都知道,实现了IDispose
接口可以使用using IServiceScope scope = HttpContext.RequestServices.CreateScope()
的方式,它编译完之后其实是
IServiceScope scope = HttpContext.RequestServices.CreateScope();
try
{
//具体操作
}
finally
{
scope.Dispose();
}
实现了IAsyncDisposable
接口可以使用await using (AsyncServiceScope scope2 = scopeProvider.CreateAsyncScope())
的方式,它编译完的代码则是
AsyncServiceScope scope2 = scopeProvider.CreateAsyncScope();
try
{
//具体操作
}
finally
{
await scope2.DisposeAsync();
}
打消了这个疑虑,相信大家对它们的关系有了了解,本质就是包装了一下IServiceScope
实例。
由创建开始
接下来我们可以专心的看一下IServiceScope
相关的实现,IServiceScope
的创建则是来自IServiceProvider
的扩展方法CreateScope()
,首先看下它的定义[点击查看源码??]
public static IServiceScope CreateScope(this IServiceProvider provider)
{
return provider.GetRequiredService().CreateScope();
}
好吧,短短的一行代码,我们可以得到两个比较重要的信息
- 首先获取到的
IServiceScopeFactory
实例,看过上篇文章的可以知道,默认情况通过IServiceScopeFactory
实例获取的是根容器
的实例。
- 其次
IServiceProvider
的CreateScope扩展方法,本质是调用的IServiceScopeFactory
的CreateScope
方法。
接下来我们就看看下IServiceScopeFactory默认实现类中关于CreateScope()
方法的定义,在ServiceProviderEngineScope
类中[点击查看源码??]
internal ServiceProvider RootProvider { get; }
public IServiceScope CreateScope() => RootProvider.CreateScope();
这里毫无疑问了RootProvider
属性里的实例都是来自根容器,而CreateScope()
方法则是调用的ServiceProvider
的CreateScope()
方法。看下ServiceProvider
类的CreateScope方法定义
[点击查看源码??]
private bool _disposed;
internal IServiceScope CreateScope()
{
//判断当前ServiceProvider是否被释放
if (_disposed)
{
//如果已经释放则直接抛出异常
ThrowHelper.ThrowObjectDisposedException();
}
//创建ServiceProviderEngineScope实例
return new ServiceProviderEngineScope(this, isRootScope: false);
}
通过上面的代码我们可以看到CreateScope()
方法,本质是创建了一个ServiceProviderEngineScope
方法实例。通过创建的这一行代码,好巧不巧又可以得到两个重要的信息。
- 一是ServiceProviderEngineScope构造函数的第一个参数,传递的是当前的ServiceProvider实例。
- 二是ServiceProviderEngineScope构造函数的第二个参数叫
isRootScope
值给的是false
,说明当前ServiceProviderEngineScope实例不是根作用域,也就是我们说的子作用域。
大致看一下ServiceProviderEngineScope构造函数的实现[点击查看源码??]
internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
internal Dictionary ResolvedServices { get; }
internal object Sync => ResolvedServices;
internal ServiceProvider RootProvider { get; }
public bool IsRootScope { get; }
//IServiceProvider的ServiceProvider属性则是赋值的当前实例
public IServiceProvider ServiceProvider => this;
public ServiceProviderEngineScope(ServiceProvider provider, bool isRootScope)
{
//用来存储当前作用域管理的对象实例
ResolvedServices = new Dictionary();
//创建当前实例的根容器
RootProvider = provider;
//标识当前作用域是否是根容器
IsRootScope = isRootScope;
}
}
下大致看一下,因为接下来会涉及到ServiceProviderEngineScope
这个类。到目前为止涉及到了两个比较重要的类ServiceProvider
和ServiceProviderEngineScope
,它们都是实现了IServiceProvider
接口。看起来有点乱的样子,不过我们可以姑且这么理解。ServiceProvider是IServiceProvider的直系实现类,作为IServiceProvider根容器的实现。ServiceProviderEngineScope是用于,通过IServiceProvider创建作用域时表现出来的实例,也就是非根容器的实例。
探究获取方法
关于上面的介绍,我们其实探究了一点serviceProvider.CreateScope()
,接下来我们就需要看一下关于获取的相关操作,也就是GetService
方法相关,它的使用形式是serviceScope.ServiceProvider.GetService()
。上面我们提到过ServiceProviderEngineScope
的ServiceProvider
属性实例则是当前ServiceProviderEngineScope的实例,所以我们直接去看ServiceProviderEngineScope
的GetService
方法[点击查看源码??]
internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
private bool _disposed;
internal ServiceProvider RootProvider { get; }
public object GetService(Type serviceType)
{
//判断当前实例是否释放
if (_disposed)
{
//如果已经释放则直接抛出异常
ThrowHelper.ThrowObjectDisposedException();
}
return RootProvider.GetService(serviceType, this);
}
}
看着挺乱的,各种跳转各种调用。不过本质只设计到两个类ServiceProvider
和ServiceProviderEngineScope
,先说明一下,省的大家看着整蒙圈了。通过最后一句代码,我们又能得到两个比较重要的信息。
- ServiceProviderEngineScope的GetService方法,本质是在调用RootProvider的GetService方法。通过前面咱们的源码分析可以知道
RootProvider
属性的值是ServiceProvider
实例也就是代表的根容器。
- 调用RootProvider的GetService方法的时候传递了当前ServiceProviderEngineScope实例。
接下来就可以直接找到ServiceProvider的GetService方法了,看一下里面的具体相关实现[点击查看源码??]
public sealed class ServiceProvider : IServiceProvider, IDisposable, IAsyncDisposable
{
private bool _disposed;
private ConcurrentDictionary> _realizedServices;
private readonly Func> _createServiceAccessor;
internal ServiceProviderEngine _engine;
internal ServiceProvider()
{
_createServiceAccessor = CreateServiceAccessor;
_realizedServices = new ConcurrentDictionary>();
}
internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
{
//判断当前实例是否释放
if (_disposed)
{
ThrowHelper.ThrowObjectDisposedException();
}
//缓存获取服务实例委托的字典,值为要获取实例的类型,值是创建实例的委托
//_createServiceAccessor本质是CreateServiceAccessor方法委托
Func realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
OnResolve(serviceType, serviceProviderEngineScope);
DependencyInjectionEventSource.Log.ServiceResolved(this, serviceType);
//执行realizedService委托,传递的是ServiceProviderEngineScope实例
var result = realizedService.Invoke(serviceProviderEngineScope);
System.Diagnostics.Debug.Assert(result is null || CallSiteFactory.IsService(serviceType));
return result;
}
private Func CreateServiceAccessor(Type serviceType)
{
//获取ServiceCallSite,其实就是获取要解析对象的实例相关信息
ServiceCallSite callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
DependencyInjectionEventSource.Log.CallSiteBuilt(this, serviceType, callSite);
OnCreate(callSite);
//咱们当前讨论的是Scope周期对象的问题,这个方法描述的是生命周期为ServiceLifetime.Singleton的情况,可以跳过这个逻辑
//如果是单例情况,则直接在根容器中直接去操作对象实例,和当前的ServiceProviderEngineScope无关
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
{
object value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
return scope => value;
}
//解析ServiceCallSite里的信息
return _engine.RealizeService(callSite);
}
return _ => null;
}
}
这里我们看下CallSiteFactory.GetCallSite
方法,先来说一下这个方法是做啥的。我们要获取某个类型的实例(可以理解为我们演示示例里的Person类),但是我们注册类相关的信息的时候(比如上面的services.AddScoped(provider => new() { Id = 1, Name = "yi念之间", Sex = "Man" })
)涉及到几种方式,比如AddScoped
和Add(Func)
,我们需要知道创建类型实例的时候使用哪种方式(比如我们的Person是使用委托的这种方式),ServiceCallSite正是存储的类型和如何创建这个类型的工厂相关的信息。我们来看一下GetCallSite
方法的核心操作[点击查看源码??]
private readonly ConcurrentDictionary _callSiteCache = new ConcurrentDictionary();
private ServiceCallSite TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, int slot)
{
if (serviceType == descriptor.ServiceType)
{
//要获取的类型会被包装成ServiceCacheKey
ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot);
//在缓存中获取ServiceCallSite实例,可以理解为设计模式中的享元模式
if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite serviceCallSite))
{
return serviceCallSite;
}
ServiceCallSite callSite;
//根据ServiceDescriptor.Lifetime包装ResultCache
var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);
//ServiceDescriptor就是我们添加到IServiceCollection的最终形式
//我们注册服务的时候本质就是在IServiceCollection里添加ServiceDescriptor实例
//AddScope()这种形式
if (descriptor.ImplementationInstance != null)
{
callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance);
}
//AddScope(Func)形式
else if (descriptor.ImplementationFactory != null)
{
callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);
}
//AddScope()形式
else if (descriptor.ImplementationType != null)
{
callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain);
}
else
{
throw new InvalidOperationException(SR.InvalidServiceDescriptor);
}
//将创建的ServiceCallSite缓存起来
return _callSiteCache[callSiteKey] = callSite;
}
return null;
}
而解析ServiceCallSite
实例的方法RealizeService(ServiceCallSite)
则是在ServiceProviderEngine
类中,看一下相关实现[点击查看源码??]
public override Func RealizeService(ServiceCallSite callSite)
{
int callCount = 0;
return scope =>
{
//核心代码是Resolve方法,这里的scope则是ServiceProviderEngineScope
//即我们上面通过CreateScope()创建的实例
var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
if (Interlocked.Increment(ref callCount) == 2)
{
_ = ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
try
{
_serviceProvider.ReplaceServiceAccessor(callSite, base.RealizeService(callSite));
}
catch (Exception ex)
{
//省略掉非核心代码
}
},
null);
}
return result;
};
}
上面我们看到的RealizeService()
方法返回的是一个委托,而调用这个委托的地方则是上面源码中看到的realizedService.Invoke(serviceProviderEngineScope)
,核心操作在CallSiteRuntimeResolver.Instance.Resolve()
方法,Resolve方法的核心逻辑在VisitCallSite()
方法,看一下它的实现方式[点击查看源码??]
protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
if (!_stackGuard.TryEnterOnCurrentStack())
{
return _stackGuard.RunOnEmptyStack((c, a) => VisitCallSite(c, a), callSite, argument);
}
switch (callSite.Cache.Location)
{
//ServiceLifetime.Singleton单例情况
case CallSiteResultCacheLocation.Root:
return VisitRootCache(callSite, argument);
//ServiceLifetime.Scoped作用域情况,也就是咱们关注的情况
case CallSiteResultCacheLocation.Scope:
return VisitScopeCache(callSite, argument);
//ServiceLifetime.Transient瞬时情况
case CallSiteResultCacheLocation.Dispose:
return VisitDisposeCache(callSite, argument);
case CallSiteResultCacheLocation.None:
return VisitNoCache(callSite, argument);
default:
throw new ArgumentOutOfRangeException();
}
}
因为我们关注的是CallSiteResultCacheLocation.Scope
这种情况所以我们重点关注的是VisitScopeCache()
这段方法逻辑,CallSiteRuntimeResolver的VisitCache()
方法[点击查看源码??]
protected override object VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
{
//咱们关注的是Scope的情况,所以重点在VisitCache方法
return context.Scope.IsRootScope ?
VisitRootCache(callSite, context) :
VisitCache(callSite, context, context.Scope, RuntimeResolverLock.Scope);
}
//这里的serviceProviderEngine参数就是我们传递进来的ServiceProviderEngineScope实例
private object VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
{
bool lockTaken = false;
//获取ServiceProviderEngineScope的Sync属性
object sync = serviceProviderEngine.Sync;
//获取ServiceProviderEngineScope的ResolvedServices属性
Dictionary resolvedServices = serviceProviderEngine.ResolvedServices;
//加锁
if ((context.AcquiredLocks & lockType) == 0)
{
Monitor.Enter(sync, ref lockTaken);
}
try
{
//判断ServiceProviderEngineScope的ResolvedServices的属性里是否包含该类型实例
//当前作用域内只有一个实例,所以缓存起来
if (resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved))
{
return resolved;
}
//当前Scope没创建过实例的话则创建
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
//判断当前类型实例是否是IDispose想实例
serviceProviderEngine.CaptureDisposable(resolved);
//给ServiceProviderEngineScope的ResolvedServices的属性添加缓存实例
resolvedServices.Add(callSite.Cache.Key, resolved);
return resolved;
}
finally
{
if (lockTaken)
{
Monitor.Exit(sync);
}
}
}
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
//比如我们上面的services.AddScoped(provider => new() { Id = 1, Name = "yi念之间", Sex = "Man" })
//对应的Kind则是CallSiteKind.Factory
switch (callSite.Kind)
{
case CallSiteKind.Factory:
//调用了VisitFactory方法
return VisitFactory((FactoryCallSite)callSite, argument);
case CallSiteKind.IEnumerable:
return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
case CallSiteKind.Constructor:
return VisitConstructor((ConstructorCallSite)callSite, argument);
case CallSiteKind.Constant:
return VisitConstant((ConstantCallSite)callSite, argument);
case CallSiteKind.ServiceProvider:
return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
default:
throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
}
}
protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
{
//调用我们注册的services.AddScoped(provider => new() { Id = 1, Name = "yi念之间", Sex = "Man" })
//FactoryCallSite的Factory即是provider => new() { Id = 1, Name = "yi念之间", Sex = "Man" }
//context.Scope则是我们通过CreateScope创建的实例
//返回的结果就是调用当前委托得到的实例即我们实例中的Person实例
return factoryCallSite.Factory(context.Scope);
}
回过头来说一下咱们上面展示的代码,被调用执行的地方就是GetService
方法里的realizedService.Invoke(serviceProviderEngineScope)
的这段代码。上面的执行逻辑里涉及到了ServiceProviderEngineScope
里的几个操作,比如ResolvedServices
属性和CaptureDisposable()
方法,看一下相关的代码
internal sealed class ServiceProviderEngineScope : IServiceScope, IServiceProvider, IAsyncDisposable, IServiceScopeFactory
{
internal IList