Core官方DI解析(4)--CallSiteRuntimeResolver
CallSiteRuntimeResolver
类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>
这个类型,也是使用了访问者模式,下面一一来解析此类
ServiceProviderEngineScope
在解析`CallSiteRuntimeResolver`之前先看一下`ServiceProviderEngineScope`类型,这个类型就可以是一个容器类型,最后实例化的服务对象就缓存在此类之中,
从下面代码中可以看出此类实现了`IServiceScope`和`IServiceProvider`两个接口,并且此类型拥有两个字段
_disposables:IDisposabl集合,此字段缓存的时所有实现了IDisposable接口的注册服务,以便在释放此容器实例时并将这些服务一起释放
_disposed:判断此属性是否已被是否释放
internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
{
private List<IDisposable> _disposables;
private bool _disposed;
}
在此类中还具有两个属性,一个是缓存实例对象的集合和一个**ServiceProviderEngine**类型的属性,从下面可以看出缓存集合使用了是`ServiceCacheKey`作为缓存的key,
而Engine是引擎类型,此属性通过构造函数传入,并且所有容器共享一个`ServiceProviderEngine`,也就是共享容器共享注册的服务
// 缓存的实例对象集合
internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; } = new Dictionary<ServiceCacheKey, object>();
// 所有ServiceProviderEngineScope对象共享一个ServiceProviderEngine
public ServiceProviderEngine Engine { get; }
// 构造函数
public ServiceProviderEngineScope(ServiceProviderEngine engine)=> Engine = engine;
这个类中一共具有四个方法,
- GetService():获取对象,可以看到此方法调用的Engine的GetService(),这个方法到
ServiceProviderEngine
时再看- ServiceProvider():这个方法返回的是当前对象
- Dispose():释放当前容器,可以看到在释放当前容器时会把_disposables集合中所有实例进行释放,并把_disposed属性设置TRUE
- CaptureDisposable():这个方法缓存要被的释放的服务实例
public object GetService(Type serviceType)
{
if (_disposed)
// 如果已被释放,就不能调用此方法
ThrowHelper.ThrowObjectDisposedException();
return Engine.GetService(serviceType, this);
}
public IServiceProvider ServiceProvider => this;
public void Dispose()
{
lock (ResolvedServices)
{
if (_disposed)
return;
_disposed = true;
if (_disposables != null)
{
for (var i = _disposables.Count - 1; i >= 0; i--)
{
var disposable = _disposables[i];
disposable.Dispose();
}
_disposables.Clear();
}
ResolvedServices.Clear();
}
}
// 缓存所有需要清理的服务实例
internal object CaptureDisposable(object service)
{
if (!ReferenceEquals(this, service))
{
if (service is IDisposable disposable)
{
lock (ResolvedServices)
{
if (_disposables == null)
_disposables = new List<IDisposable>();
_disposables.Add(disposable);
}
}
}
return service;
}
CallSiteRuntimeResolver
上面说过CallSiteRuntimeResolver
这个类型是创建和获取服务实例类型的访问者,这个类型泛型参数分别为RuntimeResolverContext
类型和实例对象类型Object
internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>{}
RuntimeResolverContext
类型是一个ServiceProviderEngineScope
封装类型,这个类型中具有一个ServiceProviderEngineScope
类型属性和一个RuntimeResolverLock
枚举类型属性,这个枚举类型在实例化对象时当做了锁使用
internal struct RuntimeResolverContext
{
public ServiceProviderEngineScope Scope { get; set; }
// 锁
public RuntimeResolverLock AcquiredLocks { get; set; }
}
[Flags]
internal enum RuntimeResolverLock
{
Scope = 1,
Root = 2
}
在CallSiteRuntimeResolver
类型中拥有两类方法,
- 根据注册服务的生命周期进行访问服务实例对象
- 根据ServiceCallSite的设置类型进行访问服务实例对象
这两个类都在其CallSiteVisitor<TArgument, TResult>
基类中
// 根据服务对象的生命周期进行访问访问实例
protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
// 缓存位置由ServiceCallSite内部的Cache属性的Location提供
switch (callSite.Cache.Location)
{
case CallSiteResultCacheLocation.Root:
return VisitRootCache(callSite, argument);
case CallSiteResultCacheLocation.Scope:
return VisitScopeCache(callSite, argument);
case CallSiteResultCacheLocation.Dispose:
return VisitDisposeCache(callSite, argument);
case CallSiteResultCacheLocation.None:
return VisitNoCache(callSite, argument);
default:
throw new ArgumentOutOfRangeException();
}
}
// 根据其ServiceCallSite的Kind属性访问服务对象
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
switch (callSite.Kind)
{
case CallSiteKind.Factory:
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);
case CallSiteKind.ServiceScopeFactory:
return VisitServiceScopeFactory((ServiceScopeFactoryCallSite)callSite, argument);
default:
throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported");
}
}
这两个方法内部调用的方法部分被CallSiteRuntimeResolver
类中重写,
下面先来看看根据生命周期进行访问的一系列方法
VistRootCache:
这个方法是访问Root生命周期的方法,可以看到这个在这个方法调用了一个VisitCache(),这个方法一共四个参数,第一个,第二个分别是当前方法函数。第三个参数代表容器对象,容器使用的是
ServiceProviderEngine
实例中的Root属性,这个容器代表了顶级容器,这也就是Root生命周期的本质,使用的顶级容器进行创建/获取实例,第四个参数锁,此方法使用的是RuntimeResolverLock.Root锁VisitScopeCache:
这个方法是访问Scoped生命周期方法,此方法和上面方法相似,也是调用了VisitCache(),但是不同的是是锁不同,这个锁是根据当前容器来决定,如果当前容器为顶级容器,就使用Root锁,所以不为顶级容器,则使用Scope锁
VisitDisposeCache
这个方法访问transient生命周期方法,可以看到这个方法直接调用VisitCallSiteMain()进行获取实例对象,然后调用CaptureDisposable()将此对象尝试缓存到ServiceProviderEngineScope容器的_disposables集合中
VisitNoCache
这个方法代表不缓存,这个方法在
CallSiteRuntimeResolver
类中未重写,所以直接调用的CallSiteVisitor
类型的VisitNoCache(),也基类中直接调用VisitCallSiteMain()
//// CallSiteRuntimeResolver
// 访问Root生命周期方法
protected override object VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
=> VisitCache(singletonCallSite, context, context.Scope.Engine.Root, RuntimeResolverLock.Root);
// 访问Scoped生命周期方法
protected override object VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
{
// 如果当前容器为根容器,则将其锁转换为Root,否则为Scope
var requiredScope = context.Scope == context.Scope.Engine.Root ?
RuntimeResolverLock.Root :
RuntimeResolverLock.Scope;
return VisitCache(singletonCallSite, context, context.Scope, requiredScope);
}
// 访问transient生命周期方法
protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
=> context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
//// CallSiteVisitor
// 无缓存
protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
=> VisitCallSiteMain(callSite, argument);
**VisitCache()**这个方法是使用指定的容器进行实例化并缓存服务实例对象,在下面代码中可以看到,代码中根据**RuntimeResolverContext**实例的枚举值与第四个参数进行,如果不相同,则进行加锁。然后进行获取实例服务对象,如果已缓存则直接获取,没有缓存则调用**VisitCallSiteMain()**获取实例并缓存
private object VisitCache(ServiceCallSite scopedCallSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
{
bool lockTaken = false;
// 获取容器中的缓存服务实例属性
var resolvedServices = serviceProviderEngine.ResolvedServices;
if ((context.AcquiredLocks & lockType) == 0)
// 如果当前枚举值与RuntimeResolverContext的枚举值不相同,则加锁
Monitor.Enter(resolvedServices, ref lockTaken);
try
{
// 如果当前数据并未在缓存之中,则实例化此对象并将其缓存至集合中
if (!resolvedServices.TryGetValue(scopedCallSite.Cache.Key, out var resolved))
{
// 获取实例对象
resolved = VisitCallSiteMain(scopedCallSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
// 将当前对象尝试加入到容器的_disposables集合
serviceProviderEngine.CaptureDisposable(resolved);
// 缓存实例对象
resolvedServices.Add(scopedCallSite.Cache.Key, resolved);
}
return resolved;
}
finally
{
if (lockTaken)
Monitor.Exit(resolvedServices);
}
}
**VisitCallSiteMain()**内调用的所有方法都在`CallSiteRuntimeResolver`类进行了重写,下面看看`CallSiteRuntimeResolve`类中的这些方法
VisitFactory
在VisitFactory()中直接调用了
FactoryCallSite
实例对象的工厂方法获取实例VisitIEnumerable
在VisitIEnumerable()中实例了
IEnumerableCallSite
中ServiceCallSites集合的所有对象,并组装到一个数组进行返回ConstructorCallSite
在VisitConstructor()中使用反射方法实例化对象,并且如果构造函数不为空则获取所有参数的实例对象
ConstantCallSite
在VisitConstant()中直接返回了
ConstantCallSite
中的对象VisitServiceProvider
在VisitServiceProvider()直接返回了
RuntimeResolverContext
封装的容器VisitServiceScopeFactory
在VisitServiceScopeFactory()中则直接返回了容器实例中引擎对象(ServiceProviderEngine)
// FactoryCallSite
protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
// 调用工厂方法进行实例化
=> factoryCallSite.Factory(context.Scope);
// IEnumerableCallSite
protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
{
var array = Array.CreateInstance(
enumerableCallSite.ItemType,
enumerableCallSite.ServiceCallSites.Length);
for (var index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
{
// 实例化IEnumerableCallSite.ServiceCallSites中所有的服务实例对象并赋值到数组中
var value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
array.SetValue(value, index);
}
return array;
}
// ConstructorCallSite
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);
}
try
{
// 根据参数对象进行实例化对象并返回
return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
}
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;
}
}
// ConstantCallSite
protected override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
// 直接返回ConstantCallSite的值
=> constantCallSite.DefaultValue;
// ServiceProviderCallSite
protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)
// 直接返回RuntimeResolverContext封装的容器
=> context.Scope;
// ServiceScopeFactoryCallSite
protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, RuntimeResolverContext context)
// 直接返回容器内的ServiceProviderEngine
=> context.Scope.Engine;
在`CallSiteRuntimeResolver`中还有叫做**Resolve()**,这个方法则是外部调用的,这个方法是由一个`ServiceCallSite`对象和一个容器对象`ServiceProviderEngineScope`,然后直接调用**VisitCallSite()**进行方法,可以看到调用此方法时**AcquiredLocks**属性并未赋值.
public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
return VisitCallSite(callSite, new RuntimeResolverContext
{
Scope = scope
});
}
Core官方DI解析(4)--CallSiteRuntimeResolver的更多相关文章
- Core官方DI解析(3)-ServiceCallSite.md
上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...
- Core官方DI解析(5)-ServiceProviderEngine
最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine在ServiceProvider的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先 ...
- Core官方DI解析(2)-ServiceProvider
ServiceProvider ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServ ...
- Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类
前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...
- abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析
老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...
- Asp.Net Core中DI的知识总结
在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...
- asp.net core的DI框架思考以及服务实例的获取方式总结
转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...
- 实战Asp.Net Core:DI生命周期
title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...
- 阅读DMA Controller Core 官方手册
阅读DMA Controller Core 官方手册 DMA控制器框架图 怎样去设定一个DMA控制器 实例化DMA控制器 参数配置界面如下图所示: 对于width of the DMA length ...
随机推荐
- 阿里如何实现海量数据实时分析技术-AnalyticDB
导读:随着数据量的快速增长,越来越多的企业迎来业务数据化时代,数据成为了最重要的生产资料和业务升级依据.本文由阿里AnalyticDB团队出品,近万字长文,首次深度解读阿里在海量数据实时分析领域的多项 ...
- shell if条件判断中:双中括号与单中括号的区别
电脑重装了系统,登录虚拟机的shell脚本需重写,在为编写的脚本命名时发现存在同名脚本,才想起来是连接公司服务器的登录脚本,不想写俩脚本,怕记混了,那就整合一下.代码如下: #!/bin/bash#z ...
- dev treelist和searchcontrol组合模糊查询用法
这里需要用到两个控件,是dev的treelist和searchcontrol,首先呢树形控件要形成树形我在这就不多说了 因为这里是记录下searchcontrol这控件的用法 首先写这三行代码,里面都 ...
- C++ 3D物理引擎库BulletPhysics基本使用
前言:最近在接触OpenGl和DX11的时候,顺便学习了Bullet这个3D物理引擎的基本使用,记录一下. |BulletPhysics介绍 BulletPhysics是一个跨平台的开源物理引擎,也是 ...
- 机器学习之决策树三-CART原理与代码实现
决策树系列三—CART原理与代码实现 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/9482885.html ID ...
- 从PRISM开始学WPF(二)Prism-更新至Prism7.1
0x1 PRISM? PRISM项目地址:https://github.com/PrismLibrary/Prism 先看下简介: Prism is a framework for building ...
- 浅析关于java的一些基础问题(上篇)
要想让一个问题变难,最基本有两种方式,即极度细化和高度抽象.对于任何语言的研究,良好的基础至关重要,本篇文章,将从极度细化的角度 来解析一些java中的基础问题,这些问题也是大部分编程人员的软肋或易混 ...
- 基础设施DevOps演进之路
Related Links:Zuul https://github.com/Netflix/zuulCAT https://github.com/dianping/cat Apollo h ...
- 图片与Base64相互转换 jar包
1.右键项目 -->Properties -->Java Bulid Path-> Libraries -->JRE System Library-->Access ru ...
- Java并发——线程介绍
前言: 互联网时代已经发展到了现在.从以前只考虑小流量到现在不得不去考虑高并发的问题.扯到了高并发的问题就要扯到线程的问题.你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法.下 ...