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. 《Head First设计模式》读书笔记

    前言:本文是记录我在阅读<Head First设计模式>这本书时,做得相关笔记,相关示例代码地址:design-patterns.由于本书不是将设计原则和设计模式分开讲述的,而是在讲一个设 ...

  2. leetcode日记本

    写在前面: 2019.6开始经过一年的学习,我依然没有学会算法,依然停留在最基本的阶段,面对题目依然一头雾水 但是难不是放弃的理由,根据毛主席的论持久战原理,我决定一天看一点循序渐进,相信总有一天可以 ...

  3. 【Java笔记】Java分包问题

    这个图讲的很清晰,转自-http://www.bubuko.com/infodetail-2219664.html

  4. rsync 守护进程及实时同步

    目录 rsync 守护进程及实时同步 rsync简介 rsync特性 rsync应用场景 cp命令 scp命令 rsync的传输方式 rsync的传输模式 rsync实际使用 rsync命令 案例 r ...

  5. JDK Httpclient 使用和性能测试

    Httpclient 使用和性能测试 上篇,通过简介和架构图,我们对HttpClient有了初步的了解. 本篇我们展示HttpClient的简单使用,同时为了说明httpclient的使用性能,我们将 ...

  6. 网络划分和各层协议以及webservice 浅谈

    最近在公司做一些和其他外部系统接口调用的工作,遇到一些网络传输的问题,趁周末的时间记录.整理一下. 提到网络我们不得不提网络的分层架构: 我们通常听到 网络七层架构/五层架构/四层架构,但是不了解很容 ...

  7. Java的generator工具类,数据库生成实体类和映射文件

    首先需要几个jar包: freemarker-2.3.23.jar log4j-1.2.16.jar mybatis-3.2.3.jar mybatis-generator-core-1.3.2.ja ...

  8. 使用 jQuery 操作页面元素的方法,实现浏览大图片的效果,在页面上插入一幅小图片,当鼠标悬停到小图片上时,在小图片的右侧出现与之相对应的大图片

    查看本章节 查看作业目录 需求说明: 使用 jQuery 操作页面元素的方法,实现浏览大图片的效果,在页面上插入一幅小图片,当鼠标悬停到小图片上时,在小图片的右侧出现与之相对应的大图片 实现思路: 在 ...

  9. 「艺蜂酒店管理系统」 · Java Swing + mysql 开发 学生毕业设计项目

    Java  Swing在社会上基本用不到,但是任有学校拿来当做结课设计,只是博主在校期间的一个项目.如果在部署过程中有问题可以加我qq68872185. 码云仓库地址:https://gitee.co ...

  10. 【VUE】VUE使用常见问题搜集

    文章目录 1.日期格式化 2.引用JSON文件中的数据 1.日期格式化 安装插件,官网:Moment.js npm install moment --save 示例: //Sat Mar 14 202 ...