Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor
CallSiteRuntimeResolver
CallSiteRuntimeResolver是实现了CallSiteVisitor之一。
提供的方法主要分三个部分
自有成员方法
- Resolve提供服务
- VisitCache
- 私有构造函数
重写父类方法
VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
调用父类VisitCallSiteMain ,并把创建出来的服务添加到context.Scope.CaptureDisposablereturn context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
object VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
- 先找对应callSite.Value是否有值如果有直接返回
- 如果没有直接调用 VisitCallSiteMain创建服务并把对象rootServiceProviderEngine内。
- 创建的服务放入callSite.Value。
if (callSite.Value is object value)
{
return value;
} var lockType = RuntimeResolverLock.Root;
ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
if (callSite.Value is object resolved)
{
return resolved;
}
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
serviceProviderEngine.CaptureDisposable(resolved);
callSite.Value = resolved;
return resolved;
VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
- 先去serviceProviderEngine.resolvedServices拿,有的话直接返回如果没拿到执行步骤2去创建。serviceProviderEngine.resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved)
- VisitCallSiteMain创建对象
- 把创建后的对象加入对应Scope的 disposable列表
- 把创建后的对象加入对应Scope的 resolvedServices列表
if (resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved))
{
return resolved;
}
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
serviceProviderEngine.CaptureDisposable(resolved);
resolvedServices.Add(callSite.Cache.Key, resolved);
return resolved;
实现父类抽象方法
- VisitConstructor
- 给构造方法提供参数(如果有参数递归调用VisitCallSite创建参数对象)
- 直接调用ServiceCallSite的ConstructorInfo反射创建对象。
object[] parameterValues;
if (constructorCallSite.ParameterCallSites.Length == 0)
{
parameterValues = Array.Empty<object>();
}
else
{
parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
for (int index = 0; index < parameterValues.Length; index++)
{
parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
}
} return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameterValues, culture: null);
- override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
直接返回CallSite对象的DefaultValue
return constantCallSite.DefaultValue; - VisitServiceProvider
return context.Scope; - override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
根据ServiceCallSites直接循环调用VisitCallSite创建实例,然后根据实例创建集合返回var array = Array.CreateInstance(
enumerableCallSite.ItemType,
enumerableCallSite.ServiceCallSites.Length);
for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
{
object value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
array.SetValue(value, index);
}
return array;
- VisitFactory
return factoryCallSite.Factory(context.Scope);
- VisitConstructor
体力活都给CallSiteFactory了
CallSiteVisitor
- 方法
VisitCallSite(ServiceCallSite callSite, TArgument argument)
- 保证Stack安全
- 根据callSite的Cache.Location去调用不同策略的Cache方法。
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();
}
VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
- 根据不同CallSiteKind去调用不同策略的创建服务方法。
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);
default:
throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
}
- 根据不同CallSiteKind去调用不同策略的创建服务方法。
- 虚方法
- TResult VisitNoCache(ServiceCallSite callSite, TArgument argument) => VisitCallSiteMain(callSite, argument);
- TResult VisitDisposeCache(ServiceCallSite callSite, TArgument argument) -> isitCallSiteMain(callSite, argument);
- TResult VisitRootCache(ServiceCallSite callSite, TArgument argument) -> VisitCallSiteMain(callSite, argument);
- TResult VisitScopeCache(ServiceCallSite callSite, TArgument argument) => VisitCallSiteMain(callSite, argument);
根据生命周期策略由子类实现对应存储机制。
- 抽象方法
- TResult VisitConstructor(ConstructorCallSite constructorCallSite, TArgument argument);
- TResult VisitConstant(ConstantCallSite constantCallSite, TArgument argument);
- TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument);
- TResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, TArgument argument);
- TResult VisitFactory(FactoryCallSite factoryCallSite, TArgument argument);
根据服务注册时的创建机制策略由子类实现对应的创建对象机制。
CallSiteVisitor负责这活怎么干!。CallSiteRuntimeResolver负责干活
- 调用 VisitCallSite在内部区分出scope并调用具体实现方法缓存方法 (CallSiteResultCacheLocation),
-> VisitCache方法
-> 但是在缓存前得先得到被缓存的对象,这时通过调用(VisitCallSiteMain)创建对象
-> VisitCallSiteMain根据提供的callsite类型去调用实现的抽象方法创建对应对象
-> 根据cache对应的方法缓存步骤1.1的结果。 - return cahce的结果。
整体的获取对象流程大约如下
CallSiteRuntimeResolver.Resolve -> CallSiteVisitor->VisitCallSite callSite.Cache.Location VisitRootCache/VisitScopeCache/ VisitDisposeCache/ VisitNoCache -> CallSiteRuntimeResolver.VisitCache/ VisitRootCache -> VisitRootCache -> CallSiteVisitor.VisitCallSiteMain 根据callSite.Kind CallSiteRuntimeResolver.VisitFactory(abstract TResult VisitFactory)递归调用 VisitCallSite
Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor的更多相关文章
- Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的?
Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的? 在asp.net core中的DI生命周期有一个Scoped是根据请求走的,也就是说在处理一次请求时, ...
- Net6 DI源码分析Part4 CallSiteFactory ServiceCallSite
Net6 CallSiteFactory ServiceCallSite, CallSiteChain abstract class ServiceCallSite ServiceCallSite是个 ...
- Net6 DI源码分析Part2 Engine,ServiceProvider
ServiceProvider ServiceProvider是对IServiceProvider实现,它有一个internal的访问修饰符描述的构造,并需要两个参数IServiceCollectio ...
- Net6 DI源码分析Part1 ServiceCollection、ServiceDescriptor、ServiceLifetime、IServiceProvider
ServiceCollection.ServiceDescriptor.ServiceLifetime.IServiceProvider Microsoft.Extensions.Dependency ...
- Net6Configuration & Options 源码分析 Part3 IOptionsMonitor 是如何接收到配置文件变更并同步数据源的
配置源的同步 IOptionsMonitor 使用 //以下demo演示使用IOptionsMonitor重新加载配置并当重新加载配置是执行回调函数 var configuration = new C ...
- 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析
目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...
- Net6 Configuration & Options 源码分析 Part2 Options
Net6 Configuration & Options 源码分析 Part2 Options 第二部分主要记录Options 模型 OptionsConfigurationServiceCo ...
- 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器
1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...
- Net6 Configuration & Options 源码分析 Part1
Net6 Configuration & Options 源码分析 Part1 在Net6中配置系统一共由两个部分组成Options 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...
随机推荐
- zabbix5.0监控安全配置全过程
第一部分,安装 此安装配置为yum方式安装zabbix5.0 系统版本:CentOS Linux release 7.5.1804 (Core) zabbix版本:rpm -qa | grep zab ...
- JZOJ5409. Fantasy && Luogu2048 [NOI2010]超级钢琴
题目大意 给出一个序列和\(L, R\), 求前k大长度在\([L,R]\)之间的连续子序列的和的和. 解题思路 朴素的想法是对于一个左端点\(p\), 它的右区间取值范围是一个连续的区间即\([p+ ...
- Android 悬浮窗 System Alert Window
悬浮窗能显示在其他应用上方.桌面系统例如Windows,macOS,Ubuntu,打开的程序能以窗口形式显示在屏幕上. 受限于屏幕大小,安卓系统中主要使用多任务切换的方式和分屏的方式.视频播放,视频对 ...
- Linux 使用 split 命令分割文件
使用方法: $ split --help 用法:split [选项]... [输入 [前缀]] 将输入内容拆分为固定大小的片段并输出到"前缀aa"."前缀ab" ...
- Selenium_POM架构(17)
POM是Page Object Model的简称,它是一种设计思想,意思是,把每一个页面,当做一个对象,页面的元素和元素之间操作方法就是页面对象的属性和行为. POM一般使用三层架构,分别为:基础封装 ...
- Eclipse导包
导包快捷键:"Ctrl+Shift+M",但是一般不用,一般利用整理包的快捷键. 整理包的快捷键:"Ctrl+Shift+O",与导包的区别在于,有用的留着,没 ...
- centos7 系统级别(持续更新)
查看当前系统级别 runlevel 获取当前级别 systemctl get-default centos7中只能通过target来设置.先获取target列表 ls -l /usr/lib/syst ...
- docker的安装以及使用命令
docker的安装 安装docker https://docs.docker.com/install/linux/docker-ce/centos/#set-up-the-repository 从 2 ...
- Pytorch之Spatial-Shift-Operation的5种实现策略
Pytorch之Spatial-Shift-Operation的5种实现策略 本文已授权极市平台, 并首发于极市平台公众号. 未经允许不得二次转载. 原始文档(可能会进一步更新): https://w ...
- 【问题排查过程】vm-backup的snapshots导致磁盘满
使用中发现,vm-storage节点仅仅过了6天,就占用了800GB的硬盘空间.很不正常.下面是排查过程: 1.查看磁盘占用情况: 先登录容器,执行: df -h /dev/vdb 1012.8G 8 ...