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 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...
随机推荐
- 教你如何6秒钟往MySQL插入100万条数据!然后删库跑路!
教你如何6秒钟往MySQL插入100万条数据!然后删库跑路! 由于我用的mysql 8版本,所以增加了Timezone,然后就可以了 前提是要自己建好库和表. 数据库test, 表user, 三个字段 ...
- linux 三剑客(持续更新)排版后续再说,边学边记笔记
切记:seq命令用于产生从某个数到另外一个数之间的所有整数.sed才是处理文本的命令 在遇到扩展符号时,需要添加特定参数,| () +[] 为扩展符号时,必须添加参数 egrep/grep -E s ...
- java运行时创建对象
有很多场景需要运行时创建对象,比如Copy对象到指定类型的对象中,比如根据指定的字段和值创建指定类型的对像.使用JDK自带的反射(java.lang.reflect)或者自省(java.beans.I ...
- 【Java常用类】String
文章目录 String String实例化的方式 方式一:通过字面量定义 方式二:new + 构造器的方式 String s = new String("abc")方式创建对象,在 ...
- java计算器(简单版)
前言 之前在学习完Java的方法后,我发现自己可以开始写计算器这个"经典"的项目了,于是我花了一点时间写下了这个计算器的程序,也写下了这篇文章. 在这里,我需要说明一下,这个程序只 ...
- FHQtreap(我有个绝妙的理解方法,但课的时间不够[doge])
FHQtreap板子(P1486 [NOI2004] 郁闷的出纳员) 会了FHQ,treap什么的就忘了吧...... #include<bits/stdc++.h> using name ...
- 巧用 Base62 解决字段太短的问题
最近银联一纸 259 号改造通知,所有支付机构开始改造支付交易,上传终端信息. 不知道其他支付机构的小伙伴针对这次改造是否开始了? 由于这次银联给的时间非常少,我们这边改动涉及到相关上游一起改造,所以 ...
- golang中字符串-字节切片,字符串-字符切片的互转
package main import ( "fmt" "reflect" ) func B2S(bs []uint8) string { // 将字节切片转换 ...
- ES_AutoCheck.sh
#!/bin/bash #@es_check #@date 2019/11/26 #@auth tigergao status=`curl -s GET "http://172.16.71. ...
- python 小兵(4)之文件操作
文件操作 初始文件操作 使用Python来读写文件是非常简单的操作,我们使用open()函数来打开一个文件,获取到文件句柄,然后通过文件句柄就可以进行各种各样的操作了 根据打开方式的不同能够执行的操作 ...