接着 上篇 目前也算是交代清楚了相关的类。那么框架具体是如何来实例化的呢?整个的流程是怎么样的。

我们参考源码中的Test文件夹来看看:

var collection = new ServiceCollection();
collection.AddTransient<DependOnNonexistentService>();
var provider = CreateServiceProvider(collection); protected override IServiceProvider CreateServiceProvider(IServiceCollection collection) => collection.BuildServiceProvider(); public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
{
return BuildServiceProvider(services, ServiceProviderOptions.Default);
} public class ServiceProviderOptions
{
// Avoid allocating objects in the default case
internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions(); /// <summary>
/// <c>true</c> to perform check verifying that scoped services never gets resolved from root provider; otherwise <c>false</c>.
/// </summary>
public bool ValidateScopes { get; set; } internal ServiceProviderMode Mode { get; set; } = ServiceProviderMode.Dynamic;
} internal enum ServiceProviderMode
{
Dynamic,
Runtime,
Expressions,
ILEmit
} public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
} if (options == null)
{
throw new ArgumentNullException(nameof(options));
} return new ServiceProvider(services, options);
} internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
IServiceProviderEngineCallback callback = null;
if (options.ValidateScopes)
{
callback = this;
_callSiteValidator = new CallSiteValidator();
}
switch (options.Mode)
{
case ServiceProviderMode.Dynamic:
_engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Runtime:
_engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
break;
#if IL_EMIT
case ServiceProviderMode.ILEmit:
_engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback);
break;
#endif
case ServiceProviderMode.Expressions:
_engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback);
break;
default:
throw new NotSupportedException(nameof(options.Mode));
}
}

如上所示,就是注入服务,实例化服务的整个过程了。我们主要是根据IServiceCollection的扩展方法BuilServiceProvider调用ServiceProvider类,进而实例化相关服务。

除去这种方式实现ServiceProvider外,默认asp.net core框架中还有一个DefaultServiceProviderFactory。不过这个工厂类最后也是调用IServiceCollection接口的拓展方法--BuildServiceProvider来创建ServiceProvider类。

总结:
IServiceCollection接口的拓展方法Addxxx 收集需要注入的服务,服务实现类型,服务的生命周期。这些就是在ServiceDescriptor中获取到的,也是该类的属性对象。这个也是IServiceCollection继承自IList<ServiceDescriptor>的解释所在。随后再获取ServiceProviderOptions枚举对象,选择实现实例化的类型,比如反射等。最后就是调用BuildServiceProvider来生成ServiceProvider了。ServiceProvider根据选择之前的选择及配置,实例化服务。

除去最后使用反射等来实例化服务之外,可以看出asp.net core的DI框架的设计思路是这样的:
将需要服务对象抽象化,首先,一个服务要进行DI,需要知道的是服务对象,实例对象,服务生命周期。将这三点抽象成一个ServiceDescriptor服务描述符对象。
由于需要DI的服务有很多,因此抽象出来一个容器来存储每个服务的三大对象(我们只叙述重要,常用的三个对象),也就是我们上面抽象出来的描述符对象。这个容器我们使用ServiceCollection来表示,它继承自IServiceCollection,而IServiceCollection其实就是IList<ServiceDescriptor>的集合,代表着众多的注入服务。服务的实例化我们抽象出来一个类:ServiceProvider,它实现一个接口,该接口只有一个方法GetService,表示获取指定服务的实例。
而我们将服务的实例化放在了该类的构造函数中,同时给它传入一个ServiceDescriptor集合对象,这个对象就包裹着需要注入服务的详细信息。随后使用指定的方式(在这里其实又抽象出来了一个配置类来指定实例化服务的方式)来实例化服务。

因此,ServiceCollection提供增删功能,这是对于ServiceDescriptor来存储的,ServiceDescriptor则是需要注入的服务的描述信息的抽象。ServiceProvider则是根据传入的配置类以及服务描述信息集合来实例化指定服务。

整个的设计思路其实就是一个抽象化的过程。这在设计中很有借鉴价值。

asp.net core 依赖注入实现全过程粗略剖析(2)的更多相关文章

  1. asp.net core 依赖注入实现全过程粗略剖析(1)

    转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 常用扩展方法 注入依赖服务: new ServiceCollection().AddSingle ...

  2. asp.net core 依赖注入实现全过程粗略剖析(3)

    接着 前面,前面的过程是普遍常用的依赖注入解析过程,我们正常都是在startup类中注入依赖服务,但是,笔者这周开发的时候遇到个问题,不同服务的生命周期不同,不能调用服务.举个例子,AddDbCont ...

  3. # ASP.NET Core依赖注入解读&使用Autofac替代实现

    标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...

  4. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  5. [译]ASP.NET Core依赖注入深入讨论

    原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...

  6. asp.net core 依赖注入几种常见情况

    先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...

  7. ASP.NET Core依赖注入——依赖注入最佳实践

    在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...

  8. 自动化CodeReview - ASP.NET Core依赖注入

    自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...

  9. ASP.NET Core 依赖注入最佳实践——提示与技巧

    在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...

随机推荐

  1. Python基础之常用模块

    一.time模块 1.时间表达形式: 在Python中,通常有这三种方式来表示时间:时间戳.元组(struct_time).格式化的时间字符串: 1.1.时间戳(timestamp) :通常来说,时间 ...

  2. poj2728 生成树01分数规划 (二分答案)

    给定整数序列a,b,求出下式的最大值 sum{ai*xi}/sum{bi*xi},xi=0|1 通俗来说,就是选出一些整数对(ai,bi),使得选出的a之和与选出的b之和商最大化 二分答案L,即选出的 ...

  3. Gson解决字段为空是报错的问题

    json解析有很多工具,这里说的是最常用也是解析速度最快的Gson,Gson是google家出的,有一个缺点就是无法设置null替换, 我们只能手动的批量替换服务器返回的null了,正常的接口定义的时 ...

  4. java.net.ConnectException: Call From slaver1/192.168.19.128 to slaver1:8020 failed on connection exception: java.net.ConnectException: Connection refused; For more details see: http://wiki.apache.org

    1:练习spark的时候,操作大概如我读取hdfs上面的文件,然后spark懒加载以后,我读取详细信息出现如下所示的错误,错误虽然不大,我感觉有必要记录一下,因为错误的起因是对命令的不熟悉造成的,错误 ...

  5. 各厂商服务器存储默认管理口登录信息(默认IP、用户名、密码)收集

    666:https://blog.csdn.net/xiezuoyong/article/details/84997917

  6. (4).NET CORE微服务 Micro-Service ---- Consul服务发现和消费

    上一章说了  Consul服务注册  现在我要连接上Consul里面的服务 请求它们的API接口 应该怎么做呢? 1.找Consul要一台你需要的服务器 1.1 获取Consul下的所有注册的服务 u ...

  7. lr场景异常Continuing after Error -26479: Conversion of form submission data to the target charset failed: U_TRUNCATED_CHAR_FOUND解决方法

    在lr压测场景中执行,发现 一个事务都没有成功,很是奇怪,发现用linux的agent各种问题 查看lr运行日志 看到这里基本确定是编码的问题,然后想起lr设置编码的地方就那么几个,所以逐个尝试 改完 ...

  8. window上安装zabbix agent使用案例

    下载对应的zabbix windows版本 因为zabbix server使用的版本为3.2.0版本 所以下载window 3.2的版本 https://www.zabbix.com/download ...

  9. nginx限制单个IP的最大连接数量限制下载速度

    今天seafile服务因为测试在下载文件的时候,带宽占用过大,导致seafile客户端无法登陆的问题. 我们公司的seafile是通过nginx代理的8000端口,因此我这边通过修改nginx配置来解 ...

  10. net core体系-API-1Ocelot-(1)概要

    从这篇开始探讨Ocelot,Ocelot是一个.NET API网关,仅适用于.NET Core,用于.NET面向微服务/服务的架构中.当客户端(web站点.ios. app 等)访问web api时, ...