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. 第三十三个知识点:Bellcore攻击是如何攻击使用CRT的RSA的?

    第三十三个知识点:Bellcore攻击是如何攻击使用CRT的RSA的? 注意:这篇博客是由follow论密码计算中消除错误的重要性(On the importance of Eliminating E ...

  2. 「HAOI 2006」数字序列

    Description 给定一长度为 \(n\) 的数列 \(a\),可将 \(a_i\) 改为任意整数 \(k\),代价为 \(\mid a_i-k\mid\). 问最少改变多少个数能把它变成一个单 ...

  3. pandas tutorial

    目录 Series 利用dict来创建series 利用标量创建series 取 Dataframe 利用dict创建dataframe 选择 添加列 列移除 行的选择, 添加, 移除 Panel B ...

  4. 【Azure 应用服务】探索在Azure上设置禁止任何人访问App Service的默认域名(Default URL)

    问题描述 总所周知,Azure App Service服务会默认提供一个 ***.chinacloudsites.cn为后缀的域名,但是该域名由上海蓝云网络科技有限公司备案,仅用于向其客户提供 Azu ...

  5. 标准基座获取定位可以获取address城市,自定义基座获取不到address

    正常的返回应该 { "type": "WGS84", "altitude": 0, "latitude": 31.830 ...

  6. 使用PyTorch构建神经网络以及反向传播计算

    使用PyTorch构建神经网络以及反向传播计算 前一段时间南京出现了疫情,大概原因是因为境外飞机清洁处理不恰当,导致清理人员感染.话说国外一天不消停,国内就得一直严防死守.沈阳出现了一例感染人员,我在 ...

  7. Zookeeper基础教程(三):Zookeeper连接使用—zkCli

    上一篇介绍Zookeeper的安装,并介绍了使用ZooInspector连接Zookeeper,这里主要介绍以命令行的形式介绍Zookeeper 假如我们已经安装了Zookeeper集群,集群中的安装 ...

  8. CF612E Square Root of Permutation

    题目分析 我们首先模拟一下题意 假设有一个 \(q _1\) \(p\) \(a_1\) \(a_x\) \(a_{a_1}\) \(a_{a_x}\) \(q\) \(x\) \(a_1\) \(a ...

  9. .NET 微服务——CI/CD(4):避坑和一点经验

    如果你看过之前几篇文章,应该已经Jenkins成功搭建了CICD环境,但是进入正式环境会有一些坑,不注意中招的话很难受,这里总结一下,避免重复消耗精力. 后门漏洞 Jenkins有后门,这是个老问题了 ...

  10. Linux上天之路系列目录

    Linux上天之路系列目录 Linux上天之路(一)之Linux前世今生 Linux上天之路(二)之Linux安装 Linux上天之路(三)之Linux系统目录 Linux上天之路(四)之Linux界 ...