Core官方DI解析(5)-ServiceProviderEngine
最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine在ServiceProvider的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先来看一下IServiceProviderEngine接口和其实现类的整体结构
IServiceProviderEngine类型继承关系
internal interface IServiceProviderEngine : IDisposable, IServiceProvider
{
IServiceScope RootScope { get; }
}
`IServiceProvderEngine这个接口`继承了`IServiceProvider`接口,也就是说工作引擎也具有**GetService()**方法,在此接口中具有一个`IServiceScope`类型的**RootScope**,而这个属性则代表是**根容器**
`IServiceScope`代表一个容器接口,这个接口中具有一个`IServiceProvider`类型的属性,返回真正表示容器的一个`IServiceProvider`类型
public interface IServiceScope : IDisposable
{
/// <summary>
/// The <see cref="System.IServiceProvider"/> used to resolve dependencies from the scope.
/// </summary>
IServiceProvider ServiceProvider { get; }
}
IServiceProviderEngine整体结构
IServiceProviderEngine
- ServiceProviderEngine
- CompiledServiceProviderEngine
- DynamicServiceProviderEngine
- RuntimeServiceProviderEngine
- ILEmitServiceProviderEngine
- ExpressionsServiceProviderEngine
上面是目前整个引擎结构,但是前面说过目前只用到了`DynamicServiceProviderEngine`,但是我们看整个类型会看到其实在这几个派生类型中只有一个实现方法`RealizeService(ServiceCallSite callSite)`,而整体结构都是在基类`ServiceProviderEngine`类型中,下面来看看这个基类类型
ServiceProviderEngine
`ServiceProviderEngine`类型是整个结构的核心类型,但是这个类也是一个很简单的类,这个类只是调用`CallSiteFactory`和`CallSiteRuntimeResolver`,由下图可以看到这个类型是一个抽象类,并且实现了`IServiceProviderEngine`和`IServiceScopeFactory`接口接口
`IServiceScopeFactory`这个接口提供了一个创建子容器方法我们已知道`IServiceProviderEngine`接口*继承*了`IServiceProvider`接口,那么也就是说在`ServiceProviderEngine`已经具备以下两个功能
1.获取服务实例对象
2.创建子容器
internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory{}
// 创建子容器接口
public interface IServiceScopeFactory
{
//
IServiceScope CreateScope();
}
下面首先来看一下此类中拥有的字段+属性,这些属性都是在构造器中进行了实例化
_callback:
这个字段就是顶级容器时检查scoped生命周期的访问者对象,这个从
ServiceProvider类中时进行传入的,在这里并不细讲这个类型RealizedServices:
这个属性是缓存根据容器获取服务实例对象委托,其中Key为ServiceType
_createServiceAccessor:
这是一个根据类型获取一个根据容器获取服务实例对象的委托,可以看到使用了一个CreateServiceAccessor()进行赋值,CreateServiceAccessor()是此类型的一个核心方法,下面介绍
CallSiteFactory:
ServiceCallSite工厂类型,在构造器中实例化,可以看到实例化时将serviceDescriptors进行传入,并且可以看到在构造器中向此实例对象中添加了一个IServiceProvider和IServiceScopeFactoryRuntimeResolver:
这个属性是是获取服务实例的访问者对象,可以看到在构造器中进行传入
Root:
Root代表是一个顶级容器
ServiceProviderEngineScope类型则是一个具体的容器类型,这个类型中缓存了所有的具体服务实例对象,这个类型实现了IServiceScope接口,从下面代码可以看到RootScope其实就是直接返回了Root属性RootScope:
这也是一个根容器实例对象,直接返回的Root属性
// 顶级容器时scoped生命周期实例检查策略
private readonly IServiceProviderEngineCallback _callback;
// 根据类型创建构建服务的委托
private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor;
// 此实例是否被销毁
private bool _disposed;
// 缓存根据容器获取服务实例的委托, Key为注册类型
internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; }
// CallSite工厂类属性,此类型用于根据指定实例化方式来创建对应的CallSite
internal CallSiteFactory CallSiteFactory { get; }
// 访问者对象,此对象对进行实例和缓存具体真正的对象
protected CallSiteRuntimeResolver RuntimeResolver { get; }
// 根容器实例属性
public ServiceProviderEngineScope Root { get; }
// 根容器实例属性
public IServiceScope RootScope => Root;
// 构造器
protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
_createServiceAccessor = CreateServiceAccessor;
_callback = callback;
// 实例化根容器
Root = new ServiceProviderEngineScope(this);
// 实例化 CallSite对象访问者对象
RuntimeResolver = new CallSiteRuntimeResolver();
// 实例化CallSiteFactory类型对象
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
// 缓存一个ServiceScopeFactoryCallSite服务,相当于缓存一个ServiceProviderEngine,根据此对象进行创建子容器
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
// 缓存实例化对象的工厂
RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
}
`ServiceProviderEngine`类型中方法只有**GetService()**,**CreateScope()**,**CreateServiceAccessor()**,**Dispose()**和一个抽象方法**RealizeService()**,其中几个派生类中都只是实现了**RealizeService()**,这个一会再看,下面来看看`ServiceProviderEngine`类中的这几个方法
RealizeService:
这个方法由派生类继承,由指定的
ServiceCallSite缓存并获取 服务实例的委托GetService:
这个方法获取服务实例对象,可以看到具有两个此方法,并且第一个调用了第二个,并将顶级容器Root进行了传入,而在第二个方法中,获取并添加_createServiceAccessor委托,然后调用此委托进行获取服务实例
CreateScope:
这个方法是创建一个子容器对象,在这个方法中可以看到直接 new 了一个容器对象,并将当前对象进行了传入。从此可以得知为什么所有容器共享顶级容器的服务注册了
Dispose:
清除当前对象,并清除顶级容器
CreateServiceAccessor:
这个方法可以看到根据ServiceType进行获取指定
ServiceCallSite,然后再调用派生类实现的RealizeService()进行返回
// 抽象类型,子类实现
protected abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);
public object GetService(Type serviceType) => GetService(serviceType, Root);
internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
{
if (_disposed)
ThrowHelper.ThrowObjectDisposedException();
// 添加并获取根据容器对象实例化对象的方法,其方法由子类进行重写
var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor);
// 验证是否允许进行实例化对象
_callback?.OnResolve(serviceType, serviceProviderEngineScope);
return realizedService.Invoke(serviceProviderEngineScope);
}
public void Dispose()
{
_disposed = true;
Root.Dispose();
}
// 实例化的子容器
public IServiceScope CreateScope()
{
if (_disposed)
ThrowHelper.ThrowObjectDisposedException();
return new ServiceProviderEngineScope(this);
}
private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
{
// 根据基类类型获取对应的CallSite
var callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
// 缓存当前注册
_callback?.OnCreate(callSite);
return RealizeService(callSite);
}
return _ => null;
}
DynamicServiceProviderEngine和CompiledServiceProviderEngine
下面来看一下`DynamicServiceProviderEngine`和`CompiledServiceProviderEngine`这两个派生类型,从上面继承关系可以看到这两个派生类型是一个继承关系 `DynamicServiceProviderEngine`继承于`CompiledServiceProviderEngine`.
internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine{}
在这两个派生类型中都只是实现了基类的RealizeService(),下面先来看看CompiledServiceProviderEngine类的实现
可以看到CompiledServiceProviderEngine类中具有一个ExpressionResolverBuilder对象,这个类是使用表达式树生成结构,这个实例在构造函数进行创建,并且将CallSiteRuntimeResolver对象,本对象和顶级容器进行了传入,可以看到在重写的方法中是调用了ExpressionResolverBuilder对象的Build(),这个方法会生成一个Func<ServiceProviderEngineScope,Object>委托,然后缓存此委托,
注:
ExpressionResolverBuilder这个类挺复杂,我也没看懂,所以在此不介绍,有兴趣的可以直接看源码
internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
{
// 表达式树生成对象
public ExpressionResolverBuilder ExpressionResolverBuilder { get; }
// 构造函数
public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
=> ExpressionResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
// 重写RealizeService方法
protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
// 使用表达式树进行创建一个Func<ServiceProviderEngineScope,Object>委托
var realizedService = ExpressionResolverBuilder.Build(callSite);
// 直接将表达式生成的委托进行替换之前的缓存
RealizedServices[callSite.ServiceType] = realizedService;
return realizedService;
}
}
而在`RuntimeServiceProviderEngine`类中,则只是实现了**RealizeService()**,从下面代码可以看出在第一次调用时是直接调用`CallSiteRuntimeResolver`这个访问者获取的实例数据,而在第二次才调用的基类,也就是`CompiledServiceProviderEngine`进行了缓存,但是至于为什么这样干,我没有弄清。。。
internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
public DynamicServiceProviderEngine(
IEnumerable<ServiceDescriptor> serviceDescriptors,
IServiceProviderEngineCallback callback)
: base(serviceDescriptors, callback)
{
}
protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
var callCount = 0;
return scope =>
{
if (Interlocked.Increment(ref callCount) == 2)
{
// 如果当前是第二次调用,则调用父级进行缓存
Task.Run(() => base.RealizeService(callSite));
}
// 调用访问者进行根据当前容器和CallSite进行实例化服务对象
return RuntimeResolver.Resolve(callSite, scope);
};
}
}
Core官方DI解析(5)-ServiceProviderEngine的更多相关文章
- Core官方DI解析(3)-ServiceCallSite.md
上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...
- Core官方DI解析(4)--CallSiteRuntimeResolver
CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用 ...
- Core官方DI解析(2)-ServiceProvider
ServiceProvider ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServ ...
- Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类
前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...
- abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析
老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...
- Asp.Net Core中DI的知识总结
在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...
- asp.net core的DI框架思考以及服务实例的获取方式总结
转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...
- 实战Asp.Net Core:DI生命周期
title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...
- 阅读DMA Controller Core 官方手册
阅读DMA Controller Core 官方手册 DMA控制器框架图 怎样去设定一个DMA控制器 实例化DMA控制器 参数配置界面如下图所示: 对于width of the DMA length ...
随机推荐
- Maven配置ojdbc14-10.2.0.4.0.jar
对于oralce的jdbc驱动,在maven上搜索到把pom配置复制到pom.xml里进行引用的时候出现下面这种情况 <dependency> <groupId>com.ora ...
- 微信公众平台网页登录授权多次重定向跳转,导致code使用多次问题
背景:微信网站开发 昨天我负责的一个项目忽然出现了一个十分诡异的bug,进行微信授权登录的时候请求code的时候安卓手机会多次重定向调转我的接口接收code的接口(redirect_uri 微信请求调 ...
- Windows10系统:任务栏中电池图标消失问题的解决方法
一.问题: 电池图标对我们来说,基本是没有什么操作对它进行的,但这并不代表它不重要. 持续充电的时候自然觉得没什么,但一旦电脑脱离充电状态,我们还是会经常性地把鼠标放在电池图标上.只有清楚地了解电脑的 ...
- docker 部署aps.net MVC到windows容器
前提:已安装docker for windows,并且已经切换到Windows 容器 1.新建一个asp.net mvc 项目 2.项目有件=>添加=>添加容器业务流程协调程序支持 可以看 ...
- unity中ScriptableObject在assetbundle中的加载
转载请标明出处:http://www.cnblogs.com/zblade/ 以前都是写一些个人的调研博客,从今天开始,也写一些个人在开发中遇到的一些可以分享的趟坑博客,为后续的开发人员提供一些绵薄之 ...
- Python3+unitest自动化测试初探(中篇)
目录 6.生成测试报告 7.编写邮件发送工具 8.发送邮件 发布 0 86 编辑 删除 Python3+unitest自动化测试初探(中篇)(2019-04-18 01:41) 发布 3 245 编辑 ...
- (四)surging 微服务框架使用系列之网关
一.什么是API网关 API网关是一个服务器,是系统对外的唯一入口.API网关封装了系统内部架构,为每个客户端提供一个定制的API.API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入 ...
- sublime text3插件解决输入法不跟随的问题
快捷键ctrl + shift +p 输入 install package 回车,调出插件搜索器, 在搜索栏中输入 IMESupport 回车安装插件. 即可解决问题.
- [转]使用nodejs-koa2-mysql-sequelize-jwt 实现项目api接口
本文转自:https://blog.csdn.net/yibowanbo/article/details/80521849 nodejs-koa2-mysql-sequelize-jwt技术栈:nod ...
- Xamarin 开发Android应用简易教程(1)
最近领导又安排了新的项目需求,只好学习学习如何在.net环境下开发APP(原来没有接触过App开发)! 1.安装VS2017移动应用开发模块. 2.使用VS2017,主要是便利,无需配置环境等一系列麻 ...