草庐IT

ASP.NET Core依赖注入系统学习教程:5.生命周期

坚持 2023-03-28 原文

在现实生活中,生命周期一词往往代表着某些人或事物从生到死的过程,而在依赖注入框架中,生命周期中的“生与死”体现为服务实例的创建和释放。实际上对于介绍依赖注入框架的生命周期而言,就是在介绍依赖注入容器采用什么样的方式创建和释放服务实例。

多个容器之间的组织结构

在介绍生命周期之前,我们必须先对“多个容器之间的组织结构”和“服务范围”有一个基本的了解,因为某类生命周期模式的服务实例和“服务范围”息息相关的,如果该模式的服务实例不在“服务范围”进行使用,那么就失去了使用该模式的意义。“你知道我说的是哪个模式吗?”

在依赖注入框架中容器并不是作为一个单一化的结构存在。最开始会初始化一个根容器,我们可以利用根容器创建一个服务范围,创建的服务范围中就会包含一个容器,这种容器我们又称为子容器。基于这种创建方式,我们必须清楚知道一点的是:除了根容器之外,所有的子容器都包含在一个服务范围中。而对于每个服务范围而言,它可以不断向下延申创建更多服务范围,从而获得更多的子容器。以这种类似于“父子关系”不断向下延申创建,最终从表示上来看多个容器的组织会形成一个树形层次化的结构。

而对于上图中这种树形层次化的结构,仅仅是我们根据容器的创建形式主观意识上的一种逻辑结构,并非是依赖注入框架中实际的容器层次结构。从各个容器对象的引用层面来看,服务范围中的容器对象(子容器)并不需要知道自己的“父容器”是谁,它只在乎根容器对象在哪里,所以每个子容器对象只会针对根容器对象进行引用,根据这种引用情况多个容器之间的组织结构如下图所示。

在代码中如果要创建一个子容器,首先需要获取ServiceCollection对象,并调用该对象的BuildServiceProvider方法构建出根容器对象。然后使用IServiceProvider接口类型的根容器对象调用CreateScope扩展方法,该扩展方法会使用IServiceScopeFactory(服务范围工厂)来创建一个IServiceScope类型的服务范围对象,而这个服务范围对象中的ServiceProvider属性就是创建的子容器。代码创建过程如下:

 1    static void Main(string[] args)
 2         {
 3             //服务注册信息集合
 4             var serviceCollextion = new ServiceCollection();
 5 
 6             //构建根容器对象
 7             IServiceProvider rootProvider = serviceCollextion.BuildServiceProvider();
 8 
 9             //创建服务范围
10             IServiceScope scope =  rootProvider.CreateScope();
11 
12             //获取子容器对象
13             IServiceProvider subProvider = scope.ServiceProvider;  
14 
15         } // END Main()

在ASP.NET Core应用中根容器对象称为ApplicationService,服务范围中的子容器对象被称为RequesetService。对于“服务范围”的概念其实就相当于,客户端向服务器发送的一次HTTP请求范围。在具体处理每个请求时,ASP.NET Core框架会利用注册的一个中间件来针对当前请求创建一个代表服务范围的IServiceScope对象,该服务范围对象提供的容器对象RequesetService,将用来提供当前HTTP请求处理过程中所需的服务实例。当HTTP请求处理完成后,对应的服务范围将会被终结,服务范围其下的容器对象以及容器中的服务实例都会被变成垃圾对象待GC进行回收。


创建

基于“多个容器之间的组织结构”和“服务范围”的概念,促成了依赖注入框架中服务实例的3种生命周期模式:

  1. Singleton(单例);
  2. Scoped(范围);
  3. Transient(暂时);

接下来,我们首先根据这3种生命周期模式,在创建服务实例上的特点进行介绍。

Singleton:该模式的服务实例只会创建一次,保存在根容器中,并且由根容器提供。在多个同根的子容器中可以共同访问,并且不同子容器对于同一类型的访问,获取的是根容器中同一个实例,相当于单例模式的对象。

Scoped:该模式的服务实例在同一个服务范围的容器中只会创建一次,在不同的服务范围的容器中会多次创建,不同服务范围的容器保存各自创建的服务实例。在同一个服务范围的容器中,访问同一类型的实例都属于同一个,相当于在服务范围内的单例模式对象。该模式需要注意的是:如果使用根容器提供Scoped模式的服务实例,那么Scoped模式将会变成为Singleton模式。

Transient:该模式的服务实例不会在容器中进行保存。所以容器对象每次提供时都会创建一个新的服务实例,有着“即用即建,用后即弃”的特点。

 


释放

依赖注入框架中容器对服务实例的释放与.NET Core中的垃圾回收机制并不是一回事,容器对服务实例的释放仅仅针对的是实现了IDisposable接口的服务实例,具体的释放操作实际上就是调用它们的Dispose方法,而不同的生命周期模式的服务实例在释放上会有不同的策略。根据策略的释放特点可以归纳为如下两类。

Singleton:由于Singleton模式的服务实例是保存在根容器中,所以必须等到根容器对象被释放之后,Singleton模式的服务实例才会进行释放。

Scoped和Transient:由于这两种模式可以由根容器或子容器所创建,所以这两种模式的服务实例释放时机取决于创建它们的容器。如果创建它们的是根容器,则根容器释放时它们才会释放。如果创建它们的是子容器,那么子容器释放时它们才会释放。


存储列表

依赖注入框架中的容器在对服务进行存储时,会将其划分为两类:一类是用于存放已实例化服务的Realized Services列表,另一类是用于存放可释放服务实例的Disposable Services列表。

 

Realized Services列表在对Singleton和Scoped服务实例的提供上具有复用性,Singleton和Scoped提供时,首先会判断所属容器的Realized Services列表中是否存在对应的服务实例,如果Realized Services列表中存在对应的服务实例,那么就使用现有的服务实例进行提供。

如果Realized Services列表中不存在对应的服务实例,那么容器则会创建新的服务实例,并在提供之前先将新的服务实例添加到所属容器的Realized Services列表中。如果这个新创建的服务实例实现了IDisposable接口,那么这个新创建的服务实例还会被添加到所属容器的Disposable Services列表中。

对于Disposable Services列表需要强调的是,其中的存储的服务并不是已经被释放的,而是仅针对些实现了IDisposable接口的服务进行了添加。当容器对象被释放的时候,它会从自身的Disposable Services列表中提取出这些服务,并调用它们的Dispose方法,以便作为垃圾对象待GC回收。

 

有关ASP.NET Core依赖注入系统学习教程:5.生命周期的更多相关文章

  1. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  2. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  3. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  4. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  5. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  6. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  7. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  8. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  9. 在VMware16虚拟机安装Ubuntu详细教程 - 2

    在VMware16.2.4安装Ubuntu一、安装VMware1.打开VMwareWorkstationPro官网,点击即可进入。2.进入后向下滑动找到Workstation16ProforWindows,点击立即下载。3.下载完成,文件大小615MB,如下图:4.鼠标右击,以管理员身份运行。5.点击下一步6.勾选条款,点击下一步7.先勾选,再点击下一步8.去掉勾选,点击下一步9.点击下一步10.点击安装11.点击许可证12.在百度上搜索VM16许可证,复制填入,然后点击输入即可,亲测有效。13.点击完成14.重启系统,点击是15.双击VMwareWorkstationPro图标,进入虚拟机主

  10. kvm虚拟机安装centos7基于ubuntu20.04系统 - 2

    需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc

随机推荐