Net6 DI源码分析Part2 Engine,ServiceProvider
ServiceProvider
ServiceProvider
是对IServiceProvider
实现,它有一个internal
的访问修饰符描述的构造,并需要两个参数IServiceCollection
& ServiceProviderOptions
。所以可以通过 ServiceCollectionContainerBuilderExtensions
提供的扩展方法和DefaultServiceProviderFactory工厂类创建实例。
属性
Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor
ServiceProviderEngine _engine;
ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> _realizedServices;
CallSiteFactory CallSiteFactory { get; }
ServiceProviderEngineScope Root { get; }
CallSiteValidator _callSiteValidator;
默认"创建服务存取器"的“工厂方法”
方法
void Dispose()
很简单,做了一个事情,调用root
的对应Dispose。清理根容器构造出来的对象void OnCreate(ServiceCallSite callSite)
此方法被用于每次通过CallSiteFactory创建出来的callsite进行验证然后使用_callSiteValidator去验证callsite
。object GetService(Type serviceType)
很简单,调用同名方法,把root作为serviceProviderEngineScope传入。也就是你直接build出来的provider获取的服务均是root提供(废话)也经常被成为root provider(根容器的provider)。其Singleton
、Scoped
类型的生命周期相同。internal GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
很简单,根据type去realizedService如果有值拿对应的“创建服务存取器”否则创建一个默认的,也就是构造函数中初始化的 然后执行委托,把对应的serviceProviderEngineScope传入。
存取器内部会有对应的engine。并把传入参数给engine。engine内部回把创建好的对象放入这个serviceProviderEngineScope内。Func<ServiceProviderEngineScope, object> realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor);
OnResolve(serviceType, serviceProviderEngineScope);
var result = realizedService.Invoke(serviceProviderEngineScope);
return result;
Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
作为默认的“创建服务存取器”工厂方法做了如下事情- 通过CallSiteFactory获取对应的ServiceCallSite,并传入CallSiteChain。
CallSiteChain
防止循环依赖项 - 得到ServiceCallSite后调用OnCreate验证ServiceCallSite合规性。
- 如果是CallSiteResultCacheLocation.Root单例的,固定通过
CallSiteRuntimeResolver
(RuntimeServiceProviderEngine引擎的符类)产出物委托。算是对“单例”的优化。 - 其它生命周期通过_engine的RealizeService产出物委托。
ServiceCallSite callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
OnCreate(callSite);
if (callSite.Cache.Location == CallSiteResultCacheLocation.Root)
{
object value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root);
return scope => value;
}
return _engine.RealizeService(callSite);
- 通过CallSiteFactory获取对应的ServiceCallSite,并传入CallSiteChain。
IServiceScope CreateScope()
;
ServiceProvider作为所以ServiceProviderEngineScope的父节点
return new ServiceProviderEngineScope(this, isRootScope: false);
就算new 了一个新的ServiceProviderEngineScope其内部还是调用this指向的当前serviceProvider的CreateScope去创建对象.
ServiceProviderEngine GetEngine()
如何选择引擎,如果是NETFRAMEWORK ,NETSTANDARD2_0 并且支持DynamicCodeCompiled使用DynamicServiceProviderEngine引擎,否则使用RuntimeServiceProviderEngine- DynamicServiceProviderEngine:DynamicServiceProviderEngine的特性是如果同一个类型同一时刻需要创建多次,那么它会使用ILEmitResolverBuilder/ExpressionResolverBuilder
- RuntimeServiceProviderEngineRuntimeServiceProviderEngine内部调用CallSiteRuntimeResolver创建对象 此class 是应用使用反射创建。
ServiceProviderEngine engine;
#if NETFRAMEWORK || NETSTANDARD2_0
engine = new DynamicServiceProviderEngine(this);
#else
if (RuntimeFeature.IsDynamicCodeCompiled)
{
engine = new DynamicServiceProviderEngine(this);
}
else
{
// Don't try to compile Expressions/IL if they are going to get interpreted
engine = RuntimeServiceProviderEngine.Instance;
}
#endif
return engine;
构造方法
- 初始化
Root
GetEngine
构造服务引擎。- 初始化默认的
_createServiceAccessor
为CreateServiceAccessor
。 - _realizedServices为每个服务缓存一个create Service Accessor(
Func<ServiceProviderEngineScope, object>
) 以Type作为key,默认为_createServiceAccessor
也就是CreateServiceAccessor
。 - 提供内部服务注册信息
- 根据
ServiceProviderOptions Options
初始化验证
Root = new ServiceProviderEngineScope(this, isRootScope: true);
_engine = GetEngine();
_createServiceAccessor = CreateServiceAccessor;
_realizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ConstantCallSite(typeof(IServiceScopeFactory), Root));
CallSiteFactory.Add(typeof(IServiceProviderIsService), new ConstantCallSite(typeof(IServiceProviderIsService), CallSiteFactory));
if (options.ValidateScopes)
{
_callSiteValidator = new CallSiteValidator();
}
if (options.ValidateOnBuild)
{
foreach (ServiceDescriptor serviceDescriptor in serviceDescriptors)
{
ValidateService(serviceDescriptor);
}
}
- 初始化
这里ServiceProivder的功能很明确单一职责,提供服务,创建Scope,提供引擎,即使
ServiceProviderEngineScope
也有同名方法,但最终都依赖于ServiceProivder。它们仅仅是包装了以下。
ServiceProviderEngineScope
它实现了IServiceScope
IServiceProvider
IServiceScopeFactory
所以它可以获取服务,也可以创建Scope。
属性。
private List<object> _disposables;
bool IsRootScope
internal ServiceProvider RootProvider
internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; }
方法。object GetService(Type serviceType)
IServiceScope CreateScope() => RootProvider.CreateScope();
CreateScope总是调用RootProvider的同名方法也就是说每一个新的ServiceProviderEngineScope它们的父节点都是同一个。也就是ServieProvider。ServiceProvider作为所以ServiceProviderEngineScope的父节点void Dispose()
ServiceProviderEngine
一抽象类唯一的方法为RealizeService 主要这里它仅仅返回的是一个委托,此委托的具体执行由ServiceProvider
的GetService
执行
public abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);
DynamicServiceProviderEngine
该类继承了CompiledServiceProviderEngine.并重写了父类的RealizeService,其内部还是通过CallSiteRuntimeResolver服务类去创建服务,但如果统一时刻某一类型被创建多次时,它会做出替换掉该类型的“创建服务存取器”为 base.RealizeService(callSite)也就是CompiledServiceProviderEngine.RealizeService
可以说DynamicServiceProviderEngine
职责是根据某一个Type的使用频率给出个对应类型的“创建服务存取器” ,不同的“创建服务存取器” 内使用了不同的引擎。
CompiledServiceProviderEngine
CompiledServiceProviderEngine
是对ServiceProviderEngine
的实现之一
一个属性ResolverBuilder
和一个RealizeService
方法
ResolverBuilder 它通过环境去构造出具体的属性ILEmitResolverBuilder
/ExpressionResolverBuilder
调用RealizeService
方法是仅返回对应ResolverBuilder
的产出物的委托。GetService
internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
{
#if IL_EMIT
public ILEmitResolverBuilder ResolverBuilder { get; }
#else
public ExpressionResolverBuilder ResolverBuilder { get; }
#endif
public CompiledServiceProviderEngine(ServiceProvider provider)
{
ResolverBuilder = new(provider);
}
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite) => ResolverBuilder.Build(callSite);
}
RuntimeServiceProviderEngine
同样也是对抽象类ServiceProviderEngine的实现,重写抽象方法后,它内部直接返回CallSiteRuntimeResolver
的Resolve方法的产出物的委托。
public override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
return scope =>
{
return CallSiteRuntimeResolver.Instance.Resolve(callSite, scope);
};
}
>ServiceProviderEngine.Resolve总结
Engine的Resolve方法返回的均是委托最终在serviceProivder的GetService中执行,得到实例对象也就是我们的最终交给使用者的服务。engine创建对象依赖的均是ServiceCallSite它是由CallSiteFactory根据Type创建的。
IServiceScopeFactory
唯一一个方法IServiceScope CreateScope();
,ServiceProviderEngineScope
实现了此接口
IServiceScope: IDisposable
唯一一个属性IServiceProvider ServiceProvider { get; }
,ServiceProviderEngineScope
实现了此接口
Net6 DI源码分析Part2 Engine,ServiceProvider的更多相关文章
- 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源码分析Part1 ServiceCollection、ServiceDescriptor、ServiceLifetime、IServiceProvider
ServiceCollection.ServiceDescriptor.ServiceLifetime.IServiceProvider Microsoft.Extensions.Dependency ...
- Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor
CallSiteRuntimeResolver CallSiteRuntimeResolver是实现了CallSiteVisitor之一. 提供的方法主要分三个部分 自有成员方法 Resolve提供服 ...
- Net6 Configuration & Options 源码分析 Part2 Options
Net6 Configuration & Options 源码分析 Part2 Options 第二部分主要记录Options 模型 OptionsConfigurationServiceCo ...
- 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析
目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...
- .net core 轻量级容器 ServiceProvider 源码分析
首先看 ServiceCollection 的定义 //定义 public class ServiceCollection : IServiceCollection { private readonl ...
- 一个由正则表达式引发的血案 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 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...
随机推荐
- API 网关功能
反向代理和路由 - 大多数项目采用网关的解决方案的最主要的原因.给出了访问后端 API 的所有客户端的单一入口,并隐藏内部服务部署的细节. 负载均衡 - 网关可以将单个传入的请求路由到多个后端目的地. ...
- 【机器学习】Pandas库练习-获取yahoo金融苹果公司的股票数据
# 获取yahoo金融苹果公司的股票数据. # 1.分析拉取的数据,找到收盘数据列的列名. # 2.绘制收盘价格柱状图. # 3.分析拉取的数据涨跌率,股价移动平均和波动率. # 4. 找出开盘价和收 ...
- 'real'词频分析
写下来想法来自于无聊时写的代码.https://cryptopals.com/sets/1/challenges/3 The hex encoded string: 1b37373331363f781 ...
- Cython编译动态库、引用C/C++文件
将某些.py 编译成动态库 设置好要编译的module们: compile_to_c_modules = [ 'package.module' ] 将它们转换成cythonize可识别的参数: def ...
- Shell自动上传下载文件到SFTP服务器
1.说明 本文提供一个Shell脚本, 可以自动连接到SFTP服务器, 然后上传或者下载指定的文件, 进而可以使用Linux的corntab命令, 定时执行脚本上传下载文件, 实现文件的同步或者备份功 ...
- oceanbase数据库比赛总结
前言 ob数据库大赛由蚂蚁金服的oceanbase团队组织,今年是第一届,宣传很广,比赛十月份开始,但早在上半年就看见大量的宣传了,比赛也是相当的卷.我们进了复赛之后感觉要卷进决赛需要付出的时间精力都 ...
- [ unittest ] 文档粗读
参考: https://blog.csdn.net/ljl6158999/article/details/80994979 1.概念提出 unittest最初灵感来自于Junit,它有着和其他单元测试 ...
- 网络协议学习笔记(二)物理层到MAC层,交换机和VLAN,ICMP与ping原理
概述 之前网络学习笔记主要讲解了IP的诞生,或者说整个操作系统的诞生,一旦有了IP,就可以在网络的环境里和其他的机器展开沟通了.现在开始给大家讲解关于网络底层的相关知识. 从物理层到MAC层:如何在宿 ...
- Enumy:一款功能强大的Linux后渗透提权枚举工具
Enumy是一款功能强大的Linux后渗透提权枚举工具,该工具是一个速度非常快的可移植可执行文件,广大研究人员可以在针对Linux设备的渗透测试以及CTF的后渗透阶段利用该工具实现权限提升,而Enum ...
- 《剑指offer》面试题41. 数据流中的中位数
问题描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 例 ...