最通俗易懂的依赖注入之服务容器与作用域

推荐关注「码侠江湖」星标,时刻不忘江湖事

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

在上一篇文章中,我们讨论依赖注入的基本用法与生命周期。

接下来,在这篇文章中,我们继续深入了解服务容器相关的概念。

0e18be171daaa0ba149512cf0fc56b36.png

服务容器

我们回顾一下什么是服务容器。

在上一篇文章中,我们提到过,依赖注入系统中的服务容器会保存,由依赖注入系统创建的具有有效生命周期的服务实例。

「在 ASP.NET 的依赖注入系统中,服务容器有根容器和子容器之分。」

第一个在依赖注入系统中创建出来的容器就是根容器,而且只会有一个根容器存在,子容器可以有很多个。

它们的区别在于:

  • 「根容器中保存的实例对于所有子容器都是可见的。」

  • 「子容器中保存的的实例互相不可见。」

  • 「不同生命周期模式的服务实例,会被保存在不同的容器里。」

单例模式的服务实例被保存在根容器中。

作用域模式的服务实例被保存在作用域的容器中,作用域的容器就是子容器。

由于子容器互相不可见,所以作用域模式中保存的实例,只会在本作用域中生存。

瞬时模式的服务实例不会被保存在任何容器中的。

子容器示例

我们来看这个示例,演示了三种不同生命周期模式的区别:

public interface IAccount{ }
public interface IMessage{ }
public interface ITool{ }public class Base
{public Base(){Console.WriteLine($"Created:{GetType().Name}");}}public class Account: Base, IAccount {}
public class Message:Base, IMessage {}
public class Tool:Base, ITool {}public static void Main()
{// 创建服务集合var serviceCollection = new ServiceCollection().AddTransient<IAccount, Account>().AddScoped<IMessage, Message>().AddSingleton<ITool, Tool>();// 创建 ServiceProvider 对象代表的服务根容器var root = serviceCollection.BuildServiceProvider();// 创建子容器1var child1 = root.CreateScope().ServiceProvider;// 创建子容器2var child2 = root.CreateScope().ServiceProvider;// 获取子容器1的服务实例GetService<IAccount>(child1);GetService<IMessage>(child1);GetService<ITool>(child1);Console.WriteLine();// 获取子容器2的服务实例GetService<IAccount>(child2);GetService<IMessage>(child2);GetService<ITool>(child2);
}// 为验证生命周期,连续获取两次
public static void GetService<T>(IServiceProvider provider)
{provider.GetService<T>();provider.GetService<T>();
}

创建容器的代码与上一篇文章中的示例相同,这里我们主要关注两个 CreateScope 方法的使用:

var root = serviceCollection.BuildServiceProvider();
var child1 = root.CreateScope().ServiceProvider;
var child2 = root.CreateScope().ServiceProvider;

通过使用根容器的 CreateScope 方法,可以创建出 ServiceScope 对象,它就代表了服务的作用域。

每个作用域中,都有一个 ServiceProvider 对象,它代表服务容器。

我们可以通过服务根容器,去创建它的子容器。

最后,我们通过两个子容器去获取相应的服务实例:

// 获取子容器1的服务实例
GetService<IAccount>(child1);
GetService<IMessage>(child1);
GetService<ITool>(child1);Console.WriteLine();// 获取子容器2的服务实例
GetService<IAccount>(child2);
GetService<IMessage>(child2);
GetService<ITool>(child2);

Base 类中的构造函数,会在控制台中打印被创建的具体实例,因此这个示例的运行结果如下:

99e4bdc3dba29c3380290ca9c0a12e02.png

通过结果可以发现:

Account 服务的生命周期为瞬时,所以两次获取该服务的实例时,都会创建一个全新的 Account 对象。

Message 服务的生命周期是作用域,如果在同一个子容器中去获取它的服务实例,那么只会创建一个 Message 对象,而这里有两个子容器,所以创建了两个 Message 对象。

Tool 服务的生命周期是单例,单例模式的服务实例,只保存在根容器上,并且对所有子容器可见。由于两个子容器拥有同样的根容器,所以只有第一次获取时 Tool 对象才会被创建。

服务作用域

每一个新创建的服务作用域ServiceScope 对象都具有一个ServiceProvider对象,它代表的是服务容器。

「根容器可以创建子容器,子容器也可以创建子容器。」

但所有的子容器都是平级的,也就是说无论它是由谁创建的,它都是根容器的子容器,而不存在所谓的“孙子容器”。

虽然根容器与子容器是父子关系,但其实「子容器并不知道自己的父容器是谁,它们只知道根容器是谁」

在子容器的眼中,只有君没有父。

对于 ASP.NET 应用来说,服务作用域具有非常明确的边界,也就是每个 HTTP 的请求上下文。

也就是说,服务作用域的生命周期与每个请求上下文是绑定在一起的。

我们现在知道,容器有根容器和子容器之分。

其实根容器和子容器也有不同的身份,我们来看这张图:

f3d136a1e9ada45d5a8612bd0a9dd2f8.png

「顶端的是根容器,也称应用容器。」

「分支都是子容器,它们都是根据请求创建和释放的子容器,也称请求容器。」

在 ASP.NET 应用初始化过程中,会用到大量的内置服务实例,而这些服务实例都是由应用容器提供。

在具体处理某个请求的时候,ASP.NET 框架会针对当前请求,创建一个服务作用域对象。

这个服务作用域对象中的请求容器,用来提供当前请求处理过程中所需的服务实例。

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

a968f3d36d7d7c13b2b9be60ad1debdb.gif

如果喜欢我的文章,那么

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

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

dc0f8ab4ac87b1c7c3bef245aed5a44e.png

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

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

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

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

相关文章

深度学习入门(python)考试速成均方误差

均方误差 表示神经网络的输出&#xff0c;表示监督数据&#xff0c;表示数据的维度。 这里神经网络的输出y是softmax函数的输出 数组元素的索引从第一个开始依次对应数组“0”&#xff0c;“1”&#xff0c;“2”&#xff0c;...... 由于softmax函数的输出可理解为概率 由此…

postgresql select for update 多行加锁顺序_PostgreSQL和Mysql的MVCC实现机制的差异对比

任何数据库的主要要求之一就是实现可伸缩性。只有将争用&#xff08;锁定&#xff09;最小化&#xff08;如果不能一起删除&#xff09;&#xff0c;才可以实现。由于读/写/更新/删除是数据库中发生的一些主要的频繁操作&#xff0c;因此对于这些操作并发进行而不被阻塞非常重要…

WireShark抓DNS请求和回复数据报的分析

1 DNS简单理解 我们简单理解DNS功能是把域名转成IP地址,我们先发送一个NDS请求数据包到本地域名服务器去找,找不到我们就去根域名服务器去找,根域名找不到我们再把顶级域名服务器地址回复给本地域名服务器,然后本地域名服务器到顶级域名服务器去查询,如果依然找不到,同理…

12款白帽子用于黑客渗透测试的操作系统

想知道什么样的操作系统的是白帽子黑客的最爱吗?本文我们将推荐12个操作系统&#xff0c;包括一些Linux发行版&#xff0c;如Kali Linux&#xff0c;Parrot安全操作系统&#xff0c;BlackArch等。这些以安全为重点的操作系统&#xff0c;可以帮助白帽子黑客进行渗透测试&#…

jqurey操作radio总结

2019独角兽企业重金招聘Python工程师标准>>> 在我们前端的项目中&#xff0c;会经常用到radio单选按钮&#xff0c;下面给出个例子总结jquery对radio的各种操作&#xff1a; 示例如下&#xff1a; <html> <head><meta charset"UTF-8">&…

android中文离线api_比林肯法球Linken sphere浏览器更多更新指纹的国产防关联软件-VMLogin中文版浏览器...

林肯法球&#xff08;Linken Sphere&#xff09;是俄罗斯人开发的一个功能强大的浏览器&#xff0c;该工具最早出现在2017年7月&#xff0c;此外还具有“离线记录模式”功能&#xff0c;能够简化会话之间导入和导出cookie的过程。使用Linken Sphere工具开启浏览器会话时&#x…

【C语言简单说】十七:数组

** ( ิ∀ิ ) 还有两个小节就基本上简单的过了一遍C语言了&#xff0c;现在我们来讲诉什么是数组。** 字面意思&#xff1a;数组&#xff0c;数组的一个组&#xff1f;应该说一堆数值的一个集合&#xff1f;我不知道大家的年龄段在于什么阶段&#xff0c;如果学过集合的话&am…

Blazor University (12)组件 — 组件生命周期

原文链接&#xff1a;https://blazor-university.com/components/component-lifecycles/组件生命周期源代码[1]Blazor 组件具有许多我们可以重写以影响应用程序行为的虚拟方法。这些方法在组件生命周期的不同时间执行。下图概述了这些生命周期方法的流程。组件生命周期图SetPar…

如何通过css控制内容显示顺序 第二行的内容优先显示

我们有时进行网页设计时为了想让用户感兴趣的内容优先显示在前&#xff0c;又不想改动代码的先后顺序&#xff0c;要怎么操作呢&#xff1f;&#xff08;或者换种说法&#xff1a;源代码中要先看到A再看到B&#xff0c;而视觉上是先B再A&#xff09;举个简单的例子&#xff0c;…

【C语言简单说】十七:数组(补)

上一节 我们所说的数组是整数类型的对吧&#xff1f;那么我们还有其他类型 的数组&#xff0c;在这里用字符数组举例。 如下代码&#xff1a; #include<stdio.h> #include<stdlib.h> int main() {char a[5]{a,b,c,d,e};int i;for(i0;i<5;i){printf("a[%d…

WireShark之抓包过滤链接部分

1 问题 我们打开WireShark&#xff0c;开始抓包&#xff0c;然后浏览器输入http链接地址&#xff0c;那我们怎么快速在WireShark里面找到 2 解决办法 1&#xff09;在WireShark里面输入http 2 ) Ctrl F,然后选择字符串&#xff0c;然后在字符串的右边输入 我们要过滤的部分…

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

这篇文章是 ASP.NET 6 依赖注入系列文章的第二篇&#xff0c;点击上方蓝字可以阅读整个系列。在上一篇文章中&#xff0c;我们讨论了什么是依赖注入和控制反转&#xff0c;以及它的作用是什么。在这篇文章中&#xff0c;我们先演示一下依赖注入的基本用法&#xff0c; 然后再讨…

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 版本中&#…