最通俗易懂的依赖注入之生命周期

这篇文章是 ASP.NET 6 依赖注入系列文章的第二篇,点击上方蓝字可以阅读整个系列。

在上一篇文章中,我们讨论了什么是依赖注入和控制反转,以及它的作用是什么。

在这篇文章中,我们先演示一下依赖注入的基本用法, 然后再讨论生命周期模式。

e8d621a0f2a1b36a0ac2652b25048a30.png

基本用法

.NET 依赖注入组件主要涉及两个包:

<ItemGroup><PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /><PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" /></ItemGroup>

Abstractions 结尾的包中定义的是接口和基础的数据类型,具体实现则是由没有 Abstractions 结尾的包来提供。

比如依赖注入组件,抽象的接口和必要的类型都定义在Microsoft.Extensions.DependencyInjection.Abstractions的包中,具体的实现则在 Microsoft.Extensions.DependencyInjection 包中。

.NET 中的很多类库和组件,在设计的时候都会考虑这种“抽象和实现”的分离。

在 ASP.NET 依赖注入系统中,我们需要通过一个由 IServiceCollection 接口表示的集合来完成服务的注册,所以我们称它为服务集合。

你可以把服务集合理解为一个服务的花名册,服务注册其实就是在这个花名册里,登记服务类型的基本信息,以便在需要的时候,依赖注入控制系统能够找到它。

通过服务集合可以创建出服务提供对象,它表示为一个 ServiceProvider 对象,如下所示:

public  static  class  Sample01
{public  interface  IAccount{ }public  interface  IMessage{ }public  interface  ITool{ }public  class  Account: IAccount{}public  class  Message: IMessage{}public  class  Tool: ITool{}public static void Run(){// 创建服务集合var serviceCollection = new ServiceCollection();// 注册服务serviceCollection.AddTransient<IAccount, Account>();serviceCollection.AddScoped<IMessage, Message>();serviceCollection.AddSingleton<ITool, Tool>();// 创建服务提供对象var serviceProvider = serviceCollection.BuildServiceProvider();}
}

这段示例代码中,有三个接口,并分别实现了三个类。

这里的每一个接口都可以认为是一项服务,而每个类则是这个服务的具体实现。

我们可以通过服务提供对象,获取任何已经注册过的服务类型的实例,如下所示:

serviceProvider.GetService<IAccount>();
serviceProvider.GetService<IMessage>();
serviceProvider.GetService<ITool>();

服务注册

.NET 依赖注入组件采用了生命周期的方式,来管理它所提供的服务实例。

所谓的生命周期,就是指由依赖注入组件创建出来的服务实例,可以存活多久。

生命周期有三种模式:瞬时(Transient)、作用域(Scoped)、单例(Singleton)。

我们在注册服务时,必须要指定服务属于哪种生命周期模式,比如刚才的代码示例:

serviceCollection.AddTransient<IAccount, Account>();
serviceCollection.AddScoped<IMessage, Message>();
serviceCollection.AddSingleton<ITool, Tool>();

从注册方法的名称Addxxxx可以看出,注册的服务采用的生命周期模式依次为「瞬时\作用域\单例」

由于每个服务都可以有多种实现,所以在进行服务注册时,可以为同一个服务注册多个不同的实现类。

虽然可以注册服务的多个实现类,但是GetService方法只能返回其中一个实现类的实例,也就是最后注册的实现类。

如果想要获取某个服务的所有实现,我们可以看这个示例:

public  static  class Sample02
{//...public  abstract  class  Base { }public  class  Account:Base, IAccount{}public  class  Message:Base, IMessage{}public  class  Tool:Base, ITool{}public static void Run(){// 创建服务集合var serviceCollection = new ServiceCollection();// 注册服务serviceCollection.AddTransient<Base, Account>();serviceCollection.AddScoped<Base, Message>();serviceCollection.AddSingleton<Base, Tool>();// 创建服务提供对象var serviceProvider = serviceCollection.BuildServiceProvider();// 获取服务集合var services = serviceProvider.GetServices<Base>().ToList();}
}

示例中添加了一个 Base 抽象类,其它的类型都是 Base 的具体类。

这种抽象类和具体类的关系,类似接口与实现类的关系,所以也可以注册到依赖注入系统中。

使用GetServices 方法可以获取某个服务的类型集合,注意这个 Service 是复数形式。

示例中返回的是一个 Base 类集合,集合的元素就是已注册的 3 个具体类实例。

生命周期模式

通过前面的示例,我们可以发现,服务注册的方法有多个,每一个方法对应着不同的生命周期。

那么什么是生命周期呢?

简单来说,服务的生命周期代表着每一个服务实例的生存期。

为什么依赖注入系统中的服务实例要定义生命周期呢?

因为依赖注入系统,管理着整个应用的服务实例。

在我们开发应用的时候,肯定用到过单例。被设计为单例模式的对象,在整个应用的生命周期中,有且只有一个。

非单例模式的普通对象,都是随用随建,用完即丢。

既然依赖注入系统管理着整个应用的服务实例,那么不管是高贵的单例对象、还是没有人权普通对象,都是依赖注入系统中的一员。

于是,为了让依赖注入系统分辨出哪个对象属于哪种模式,就有了不同模式的生命周期。

前面我们说过,生命周期的模式有三种:瞬时、作用域和单例。

其中,瞬时和单例理解起来比较简单。

「瞬时,就是没有生存期。」

也就是说,每次从依赖注入系统中获取瞬时的服务实例时,都会创建一个全新的对象。

依赖注入系统中的服务容器不会保存它,也就是没有生存权的普通对象。

「单例,就是会一直存在,与应用同寿。」

也就是说,第一次从依赖注入系统中获取单例的服务实例时,才会创建一个全新的对象。

依赖注入系统中的服务容器会保存它,之后的每次使用都是直接从容器中获取它,也就是高贵的单例对象。

「作用域,理解起来没有那么直观,需要结合场景来说明。」

比如,在 ASP.NET 的应用中,每一个来自外部的请求,都可以理解为是一个请求作用域。不同的请求,就是不同的请求作用域。

在同一个请求作用域中,获取作用域模式的服务实例与单例模式的服务实例,具有同样的表现。

也就是说,第一次从依赖注入系统中获取服务实例时,才会创建一个全新的对象。

依赖注入系统会在服务容器中为该作用域开个单间,单独保存该对象。

当请求结束时,请求作用域会被销毁,单间自然也就没了,其中保存的对象也会随之销毁。

所以,在这种模式中生存的对象实例,都只作用于自己的域范围,不同的域不会互相干涉。

由此可见,服务一旦有了生命周期,那么依赖注入系统就可以根据需求,来保存和管理它们的实例。

更多精彩内容,请关注我▼▼

ae562763f510bb7da88151a96b62badf.gif

如果喜欢我的文章,那么

在看和转发是对我最大的支持!

(戳下面蓝字阅读)
  • ASP.NET 6 中间件系列

a9a98a733602227db0f404b47aeaef0c.png

推荐关注微信公众号:码侠江湖

                        75728f6ceb28483c6d53290b5d8a7883.png觉得不错,点个在看再走哟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cnblogs自定义皮肤css样式-星空观测者

不知不觉来Cnblogs也这么久了&#xff0c;然而Blogs提供的主题还是依旧那么复古&#xff0c;总觉得阅读起来难免枯燥&#xff0c;虽然我认为做技术不可以太过浮躁&#xff0c;但是一个美观的主题终究是吸引人眼的第一要素。 毕竟这么久了&#xff0c;在博客园还没有发现一个比较…

我的世界java版forge怎么用_我的世界电脑版MOD怎么用 我的世界pc版forge怎么安装...

我的世界由游戏本体以及启动器两部分组成&#xff0c;要玩游戏就要下载好本体再用启动器启动&#xff0c;单有游戏或者单有启动器都是玩不成的&#xff0c;想知道我的世界电脑版怎么开始&#xff0c;我的世界pc版启动器怎么用就来看看吧&#xff01;▍MOD怎么用1.安装MOD前要先…

【C语言简单说】十八:二维数组

这里可能会让大家脑袋迷糊&#xff0c;不过没事&#xff0c;多动动脑。 这一节我们来说二维数组&#xff0c;啥叫二维数组&#xff1f;之前我们那个是一维数组&#xff0c;好了&#xff0c;我们接下来大家就会慢慢的搞懂的。 我们的一维数组就像 一列排得整整齐齐的队伍&…

应用系统日志采集解决方案

概述 基于Flume MongoDB&#xff0c;对现有的多个应用系统进行日志采集。特点 采集范围每一次用户请求的请求信息。数据量大尽量减少现有系统的改动数据流图 说明&#xff1a;首先考虑的结构体系&#xff0c;是直接在应用系统中&#xff0c;将日志数据写到Flume&#xff1b;但…

每个程序员都可能犯过的10个错误

1. 面向编译器写代码&#xff0c;而不是面向用户 当人们使用编译器创建自己的 app 时&#xff0c;在把自己的想法诉诸于机器代码的过程中&#xff0c;常常会将那些可以使得编程更为简单却又冗长的语法遗忘于脑后。 无论你使用的是单字母的标识符还是更易于人脑理解的标识符&…

Xamarin效果第二十二篇之录音效果

在前面文章中简单玩了玩GIS的基本操作、Mark相关、AR、测距、加载三维白模和可扩展浮动操作;今天抽空再来分享一下录音效果;啥也不说了都在效果里:1、首次尝试了开源的Plugin.AudioRecorder结果发现没效果,也可能是我的姿势不对:https://github.com/NateRickard/Plugin.AudioRe…

从零开始来看一下Java泛型的设计

引言 泛型是Java中一个非常重要的知识点&#xff0c;在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计&#xff0c;将会涉及到通配符处理&#xff0c;以及让人苦恼的类型擦除。 泛型基础 泛型类 我们首先定义一个简单的Box类&#xff1a; public c…

php json error,PHP 7.3 中的 JSON 错误处理

PHP 7.3 为 json_encode() 和 json_decode() 函数增加的一个新特性使其更好的处理错误。这个特性「 RFC 」以 23 比 0 的投票结果被一致接受。让我们看一看在 PHP 7.2 及一下版本中是如何处理 JSON 错误的&#xff0c;以及 PHP 7.3 中新的改进。背景当前在 PHP7.2 版本中&#…

【C语言简单说】十九:二维数组循环嵌套(2)

这节直接用循环嵌套来输出二维数组了&#xff1a; 注&#xff1a;我说的队和列并不是一般说法&#xff0c;我用此比喻好让新手更好理解。 #include<stdio.h> #include<stdlib.h> int main() {int array[2][3]{1,2,3,4,5,6};//第一句 int i,j;//第二句 for(i0;i&l…

lia人是什么意思_狗狗喜欢舔人到底什么意思?毛孩的心思主人你要懂

很多人都喜欢养狗&#xff0c;因为它们忠诚、淘气、可爱。同时&#xff0c;狗狗也有很多奇怪的习惯&#xff0c;例如&#xff1a;喜欢舔人&#xff0c;喜欢追逐活动的东西等等。不过大多数狗主人通常都会有一个最想知道的问题&#xff1a;为什么狗狗总喜欢舔人&#xff0c;它们…

“爱思助手”曝为iOS木马:可绕过苹果DRM机制

一款新的iOS木马已在国内曝光&#xff0c;它可以通过PC感染未越狱的iOS设备&#xff0c;而无需利用企业证书。Palo Alto Networks指出&#xff0c;其名叫“爱思助手”(AceDeceiver)&#xff0c;目前正在影响我国的iOS用户。“爱思助手”利用了苹果数字版权管理(DRM)上的FairPla…

php运行条件,PHP配置环境要求 php运行的先决条件

类型&#xff1a;编程相关大小&#xff1a;320KB语言&#xff1a;中文 评分&#xff1a;6.6标签&#xff1a;立即下载在本教程中&#xff0c;假设用户的服务器已经安装并运行了 PHP&#xff0c;所有以 .php 结尾的文件都将由 PHP 来处理。在大部分的服务器上&#xff0c;这是 P…

【C语言简单说】二十:指针基础

。。据说指针很难 其实稍微理解概念不难。 先看百科的定义&#xff1a;在计算机科学中&#xff0c;指针&#xff08;Pointer&#xff09;是编程语言中的一个对象&#xff0c;利用地址&#xff0c;它的值直接指向&#xff08;points to&#xff09;存在电脑存储器中另一个地方的…

Javascript中的循环变量声明,到底应该放在哪儿?

不放走任何一个细节。相信很多Javascript开发者都在声明循环变量时犹 豫过var i到底应该放在哪里&#xff1a;放在不同的位置会对程序的运行产生怎样的影响&#xff1f;哪一种方式符合Javascript的语言规范&#xff1f;哪一种方式和ecma标准未来的发展 方向匹配&#xff1f;本文…

Delphi全局热键的注册

1.在窗启动时创建ATOM;(aatom:ATOM;定义在private中&#xff09; 1 if FindAtom(ZWXhotKey)0 then 2 begin 3 aatom:GlobalAddAtom(ZWXhotKey); 4 end; 5 if RegisterHotKey(Handle,aatom,MOD_ALT,$41) then 6 begin 7 MessageBox(Handle,按alta,提示,MB_OK); 8 end; 2.定义处…

【C语言简单说】二十一:双重指针基础 (完结)

其实后面这两节我是用我几年前写的教程复制过来的。。。 ’ – ’ ) ( &#xff13; )╱~~ 如有错误&#xff0c;请留言提醒哈~~~尴尬的笑。 多重指针呢其实就是指向指针的指针。 首先&#xff0c;变量大家都知道是啥意思了吧&#xff1f;一个变量是有地址的。那么指针变量也是…

精彩回顾|「源」来如此 第六期 - 开源经济与产业投资

| 作者&#xff1a;活动组、袁睿斌| 编辑&#xff1a;金心悦| 设计&#xff1a;朱亿钦4月17日 14:00&#xff0c;由开源社联合云启资本、易观分析、云赛空间&#xff0c;以及微软 Reactor 共同主办&#xff0c;由示说网提供转播支持的「源」来如此 第六期直播活动如约而至。在本…

C#趣味程序---真分数序列

问题&#xff1a;按递增顺序依次列出所有分母为40&#xff0c;分子小于40的最简真分数。 分析&#xff1a;利用最大公约数 using System;namespace ConsoleApplication1 {class Program{static void Main(string[] args){for(int i1;i<40;i){int a 40;int b i;while (b!0…

有关 php __autoload 自动加载类函数的用法

这个函数是一个自动加载类函数&#xff0c;啥事自动加载函数&#xff0c;顾名思义 &#xff0c;那就是自己就会加载类的函数&#xff08;原谅我废话了&#xff09; 我们先看下面的代码&#xff1a; <?php function __autoload($classname) {echo "helloworld";…

IP签名档PHP源码,IPCard 一款天气图标签名档源码

源码介绍本源码对接高德z地图开发者平台的API实现获取IP和天气数据并使用php将天气的图标与文字相结合&#xff0c;形成一张IP签名档图片&#xff0c;最后呈现出来使用说明首先去高德开放平台申请KEY&#xff0c;点击右上角的注册按钮并登录账号&#xff0c;进入控制台&#xf…