ServiceProvider

ServiceProvider是对IServiceProvider实现,它有一个internal的访问修饰符描述的构造,并需要两个参数IServiceCollection & ServiceProviderOptions。所以可以通过 ServiceCollectionContainerBuilderExtensions提供的扩展方法和DefaultServiceProviderFactory工厂类创建实例。

属性

  1. Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor
  2. ServiceProviderEngine _engine;
  3. ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> _realizedServices;
  4. CallSiteFactory CallSiteFactory { get; }
  5. ServiceProviderEngineScope Root { get; }
  6. CallSiteValidator _callSiteValidator;默认"创建服务存取器"的“工厂方法”

方法

  1. void Dispose()

    很简单,做了一个事情,调用root的对应Dispose。清理容器构造出来的对象

  2. void OnCreate(ServiceCallSite callSite)

    此方法被用于每次通过CallSiteFactory创建出来的callsite进行验证然后使用_callSiteValidator去验证callsite

  3. object GetService(Type serviceType)

    很简单,调用同名方法,把root作为serviceProviderEngineScope传入。也就是你直接build出来的provider获取的服务均是root提供(废话)也经常被成为root provider(根容器的provider)。其 SingletonScoped类型的生命周期相同。

  4. 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;
  5. Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)

    作为默认的“创建服务存取器”工厂方法做了如下事情

    1. 通过CallSiteFactory获取对应的ServiceCallSite,并传入CallSiteChain。CallSiteChain防止循环依赖项
    2. 得到ServiceCallSite后调用OnCreate验证ServiceCallSite合规性。
    3. 如果是CallSiteResultCacheLocation.Root单例的,固定通过CallSiteRuntimeResolver(RuntimeServiceProviderEngine引擎的符类)产出物委托。算是对“单例”的优化。
    4. 其它生命周期通过_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);
  6. IServiceScope CreateScope();

    ServiceProvider作为所以ServiceProviderEngineScope的父节点

    return new ServiceProviderEngineScope(this, isRootScope: false);

    就算new 了一个新的ServiceProviderEngineScope其内部还是调用this指向的当前serviceProvider的CreateScope去创建对象.

  7. ServiceProviderEngine GetEngine()

    如何选择引擎,如果是NETFRAMEWORK ,NETSTANDARD2_0 并且支持DynamicCodeCompiled使用DynamicServiceProviderEngine引擎,否则使用RuntimeServiceProviderEngine

    1. DynamicServiceProviderEngine:DynamicServiceProviderEngine的特性是如果同一个类型同一时刻需要创建多次,那么它会使用ILEmitResolverBuilder/ExpressionResolverBuilder
    2. 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;
  8. 构造方法

    1. 初始化Root
    2. GetEngine 构造服务引擎。
    3. 初始化默认的 _createServiceAccessorCreateServiceAccessor
    4. _realizedServices为每个服务缓存一个create Service Accessor(Func<ServiceProviderEngineScope, object>) 以Type作为key,默认为_createServiceAccessor 也就是CreateServiceAccessor
    5. 提供内部服务注册信息
    6. 根据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。

属性。

  1. private List<object> _disposables;
  2. bool IsRootScope
  3. internal ServiceProvider RootProvider
  4. internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; }

    方法。
  5. object GetService(Type serviceType)
  6. IServiceScope CreateScope() => RootProvider.CreateScope();

    CreateScope总是调用RootProvider的同名方法也就是说每一个新的ServiceProviderEngineScope它们的父节点都是同一个。也就是ServieProvider。ServiceProvider作为所以ServiceProviderEngineScope的父节点
  7. 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的更多相关文章

  1. Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的?

    Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的? 在asp.net core中的DI生命周期有一个Scoped是根据请求走的,也就是说在处理一次请求时, ...

  2. Net6 DI源码分析Part4 CallSiteFactory ServiceCallSite

    Net6 CallSiteFactory ServiceCallSite, CallSiteChain abstract class ServiceCallSite ServiceCallSite是个 ...

  3. Net6 DI源码分析Part1 ServiceCollection、ServiceDescriptor、ServiceLifetime、IServiceProvider

    ServiceCollection.ServiceDescriptor.ServiceLifetime.IServiceProvider Microsoft.Extensions.Dependency ...

  4. Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor

    CallSiteRuntimeResolver CallSiteRuntimeResolver是实现了CallSiteVisitor之一. 提供的方法主要分三个部分 自有成员方法 Resolve提供服 ...

  5. Net6 Configuration & Options 源码分析 Part2 Options

    Net6 Configuration & Options 源码分析 Part2 Options 第二部分主要记录Options 模型 OptionsConfigurationServiceCo ...

  6. 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析

    目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...

  7. .net core 轻量级容器 ServiceProvider 源码分析

    首先看 ServiceCollection 的定义 //定义 public class ServiceCollection : IServiceCollection { private readonl ...

  8. 一个由正则表达式引发的血案 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. 一些特殊字符,如“&”,“- ...

  9. Net6 Configuration & Options 源码分析 Part1

    Net6 Configuration & Options 源码分析 Part1 在Net6中配置系统一共由两个部分组成Options 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...

随机推荐

  1. API 网关功能

    反向代理和路由 - 大多数项目采用网关的解决方案的最主要的原因.给出了访问后端 API 的所有客户端的单一入口,并隐藏内部服务部署的细节. 负载均衡 - 网关可以将单个传入的请求路由到多个后端目的地. ...

  2. 【机器学习】Pandas库练习-获取yahoo金融苹果公司的股票数据

    # 获取yahoo金融苹果公司的股票数据. # 1.分析拉取的数据,找到收盘数据列的列名. # 2.绘制收盘价格柱状图. # 3.分析拉取的数据涨跌率,股价移动平均和波动率. # 4. 找出开盘价和收 ...

  3. 'real'词频分析

    写下来想法来自于无聊时写的代码.https://cryptopals.com/sets/1/challenges/3 The hex encoded string: 1b37373331363f781 ...

  4. Cython编译动态库、引用C/C++文件

    将某些.py 编译成动态库 设置好要编译的module们: compile_to_c_modules = [ 'package.module' ] 将它们转换成cythonize可识别的参数: def ...

  5. Shell自动上传下载文件到SFTP服务器

    1.说明 本文提供一个Shell脚本, 可以自动连接到SFTP服务器, 然后上传或者下载指定的文件, 进而可以使用Linux的corntab命令, 定时执行脚本上传下载文件, 实现文件的同步或者备份功 ...

  6. oceanbase数据库比赛总结

    前言 ob数据库大赛由蚂蚁金服的oceanbase团队组织,今年是第一届,宣传很广,比赛十月份开始,但早在上半年就看见大量的宣传了,比赛也是相当的卷.我们进了复赛之后感觉要卷进决赛需要付出的时间精力都 ...

  7. [ unittest ] 文档粗读

    参考: https://blog.csdn.net/ljl6158999/article/details/80994979 1.概念提出 unittest最初灵感来自于Junit,它有着和其他单元测试 ...

  8. 网络协议学习笔记(二)物理层到MAC层,交换机和VLAN,ICMP与ping原理

    概述 之前网络学习笔记主要讲解了IP的诞生,或者说整个操作系统的诞生,一旦有了IP,就可以在网络的环境里和其他的机器展开沟通了.现在开始给大家讲解关于网络底层的相关知识. 从物理层到MAC层:如何在宿 ...

  9. Enumy:一款功能强大的Linux后渗透提权枚举工具

    Enumy是一款功能强大的Linux后渗透提权枚举工具,该工具是一个速度非常快的可移植可执行文件,广大研究人员可以在针对Linux设备的渗透测试以及CTF的后渗透阶段利用该工具实现权限提升,而Enum ...

  10. 《剑指offer》面试题41. 数据流中的中位数

    问题描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 例 ...