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. 据库自增ID用完

    Mysql里int类型是4个字节,如果有符号位的话就是[-2^31,2^31-1],无符号位的话最大值就是2^32-1,也就是4294967295. 自增ID达到上限用完了之后,分为两种情况: 如果设 ...

  2. 项目启动报错怎么办?看看你Spring自动注入用对了嘛?@Autowired XxxService注入问题解决

    问题 在Controller层使用 @Autowired注入Service时,提示Bean中没有Service 在Service接口中使用 @Component注入后,启动项目问题提示: The we ...

  3. Java练习小题_猴子吃桃问题分别用for循环和while循环实现程序。

    要求说明: 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个.以后每天早上都吃了前一天剩下的一半零一个.到第10天早上想再吃时, ...

  4. 智慧巨鹿使用Rainbond落地实践,一个平台管理所有应用系统

    背景 大家好,我是北京数立通科技有限公司的李栋.最近几年,我一直负责"智慧巨鹿"这一智慧城市项目的运行与维护工作.这个项目涉及到10多家供应商开发的 30 多套智慧城市应用的运维管 ...

  5. Count Sequences

    \(考虑问题的转换,即把用n个球,分为r-l+2个部分,其中第1部分表示该区域的球值为l,第二部分表示该区域的球值为l+1\) \(......第r-l+2部分为不选该区域的球\) \(该问题等价于在 ...

  6. CentOS7添加开机启动服务或脚本

    方法一(rc.local) 改方式配置自动启动最为简单,只需要修改rc.local文件 由于在centos7中/etc/rc.d/rc.local的权限被降低了,所以需要赋予其可执行权 chmod + ...

  7. 第10组 Alpha冲刺 (4/6)(组长)

    1.1基本情况 ·队名:今晚不睡觉 ·组长博客:https://www.cnblogs.com/cpandbb/p/13982696.html ·作业博客:https://edu.cnblogs.co ...

  8. vue中form 表单常用校验封装(async-validator)

    新建一个js校验文件validate.js export const regular = { // 验证自然数 naturalNumber: /^(([0-9]*[1-9][0-9]*)|(0+))$ ...

  9. HDOJ3579Hello Kiki

    https://acm.hdu.edu.cn/showproblem.php?pid=3579 一些坑点.首先是如果说最后求得到的结果为0,那么在数学意义上这是正确的,0对于任何的确是最小的整数解,但 ...

  10. [CISCN2019 华东南赛区]Web11

    [CISCN2019 华东南赛区]Web11 写在前面 参考文章:Smarty SSTI 1.{php}{/php} Smarty已经废弃{php}标签,强烈建议不要使用.在Smarty 3.1,{p ...