跟我一起学.NetCore之依赖注入作用域和对象释放
前言
上一小节简单阐述了依赖注入及Asp.NetCore中自带依赖注入组件的常规用法,其中提到容器管控了自己创建对象的生命周期,包含了三种生命周期:Singleton、Scoped、Transient, 对于Singleton、Transient相对于Scoped来说比较好理解,其实这里面有一个作用域的概念,也可以理解为根容器和子容器的范围;上一小节中有一个例子中说到,当注入的生命周期为Scoped的时,在同一个请求内,注入的对象都是同一个,这里Asp.NetCore将每个请求作为了一个作用域,在此作用域内,生命周期为Scoped的对象就是同一个;下面简单说说作用域和对象释放的常规知识点;
正文
作用域这里可以理解为服务范围,由IServiceScope承载,如其源代码所示,每一个服务范围内都一个根容器,如下所示:
//// 摘要:// /// The System.IDisposable.Dispose method ends the scope lifetime. Once Dispose// /// is called, any scoped services that have been resolved from /// Microsoft.Extensions.DependencyInjection.IServiceScope.ServiceProvider// will be /// disposed. ///public interface IServiceScope : Object, IDisposable{// IServiceProvider 即代表容器//// 摘要:// /// The System.IServiceProvider used to resolve dependencies from the scope.// ///IServiceProvider ServiceProvider{get;}}
每一个服务范围内可以通过自身IServiceProvider创建对应的子作用域,而任何一个子作用域的IServiceProvider都有对根容器的引用,如下图结构:
每一个IServiceProvider中都会将其创建的对象存入列表中,针对于继承与IDisposable接口的类型对象会单独存放在一个列表中,当作用域IServiceScope对象的Dispose方法被调用时,最终对应IServicePorvider对应的对象列表也会清空,针对于继承与IDisposable类型的对象会调用其Dispose方法;最后导致对应作用域下容器创建的对象成为垃圾对象,被GC给回收;
在Asp.NetCore中,框架默认将其分有根作用域(与引用程序同生命周期)和请求作用域(每一个请求一个作用域),通常也会称其为根容器和请求容器,名称分别为ApplicationServices和RequestServices,在程序中获取方式如下:
通过IApplicationBuilder对象可以获取ApplicationServices
通过HttpContext.RequestServices获取RequestServices
作用域简单举例,在请求作用域下再创建子作用域,分别查看对应不同生命周期对象是否一致,新建一个WebApi项目,针对三个生命周期添加了对应文件,结构如下:
对应红框内的文件内容如下:
细心的小伙伴可能会看到,每个实现类里面都继承了IDisposable接口,这主要是后面显示释放用的,这里先不管;编辑好以上内容之后就将其进行注册,如下:
接下来就是使用了,这里通过这Action中使用,在当前的请求作用域下创建子作用域,对比每一个生命周期对象,如代码所示:
[HttpGet]
public string Get([FromServices]ITestSingleton testSingleton, [FromServices]ITestSingleton testSingleton1,[FromServices]ITestScoped testScoped, [FromServices]ITestScoped testScoped1,[FromServices]ITestTransient testTransient, [FromServices]ITestTransient testTransient1)
{//获取请求作用域(请求容器)var requestServices = HttpContext.RequestServices;//在请求作用域下创建子作用域using(IServiceScope scope = requestServices.CreateScope()){//在子作用域中通过其容器获取注入的不同生命周期对象ITestSingleton testSingleton11 = scope.ServiceProvider.GetService<ITestSingleton>();ITestScoped testScoped11 = scope.ServiceProvider.GetService<ITestScoped>();ITestTransient testTransient11 = scope.ServiceProvider.GetService<ITestTransient>();ITestSingleton testSingleton12 = scope.ServiceProvider.GetService<ITestSingleton>();ITestScoped testScoped12 = scope.ServiceProvider.GetService<ITestScoped>();ITestTransient testTransient12 = scope.ServiceProvider.GetService<ITestTransient>();Console.WriteLine("================Singleton=============");Console.WriteLine($"请求作用域的ITestSingleton对象:{testSingleton.GetHashCode()}");Console.WriteLine($"请求作用域的ITestSingleton1对象:{testSingleton1.GetHashCode()}");Console.WriteLine($"请求作用域下子作用域的ITestSingleton11对象:{testSingleton11.GetHashCode()}");Console.WriteLine($"请求作用域下子作用域的ITestSingleton12对象:{testSingleton12.GetHashCode()}");Console.WriteLine("================Scoped=============");Console.WriteLine($"请求作用域的ITestScoped对象:{testScoped.GetHashCode()}");Console.WriteLine($"请求作用域的ITestScoped1对象:{testScoped1.GetHashCode()}");Console.WriteLine($"请求作用域下子作用域的ITestScoped11对象:{testScoped11.GetHashCode()}");Console.WriteLine($"请求作用域下子作用域的ITestScoped12对象:{testScoped12.GetHashCode()}");Console.WriteLine("================Transient=============");Console.WriteLine($"请求作用域的ITestTransient对象:{testTransient.GetHashCode()}");Console.WriteLine($"请求作用域的ITestTransient1对象:{testTransient1.GetHashCode()}");Console.WriteLine($"请求作用域下子作用域的ITestTransient11对象:{testTransient11.GetHashCode()}");Console.WriteLine($"请求作用域下子作用域的ITestTransient12对象:{testTransient12.GetHashCode()}");}return "TestServiceScope";}
运行,进行请求,看打印结果:
对于Singleton来说始终不变,因为其是跟随根容器生命周期,引用程序退出才释放;
对于Scoped来说只要在自己的作用域内就是单例的;
对于Transient来说始终创建;
以上一直在说释放,下面利用继承IDisposable接口释放时会调用对应Dispoable方法的原理简单演示各个生命周期的释放时机;在Controller中增加几个Action方法,如下:
这里使用IHostApplicationLifetime中的StopApplication模拟关闭程序释放单例下的对象;运行看效果:
使用坑:不要从根容器中获取Transient生命周期的对象,因为通过根容器创建的对象不会回收,除非等到应用程序退出,这样会导致内存泄露;如下演示:
新增Action方法:
运行,发送请求看结果:
总结
作用域及对象释放就简单说这么多,容器只管理自己创建出来的对象生命周期;下一节说说使用第三方组件扩展依赖注入功能;
跟我一起学.NetCore之依赖注入作用域和对象释放相关推荐
- 跟我一起学.NetCore之依赖注入
前言 现阶段而言,依赖注入相关组件如果不会用一两个,感觉在Code的世界里肯定是落伍了,最起码得有工厂模式的思想,知道这样做的好处:提及到依赖注入,通常会关联出两个概念:Ioc(控制反转)和DI(依赖 ...
- .NetCore数据库依赖注入
这里用的是sqlserver,postgreSQL也可以使用(mysql没试过,不过应该都能用) 1.项目引用Nuget包 我的项目是.net5框架的,所以不是使用的最新的包 1.)引用System. ...
- .NetCore的依赖注入
//MVC自带的三种依赖注入方式 //MVC自带的三种依赖注入方式public WeatherForecastController(ILogger<WeatherForecastControll ...
- 理解AngularJS中的依赖注入
作者 CraftsCoder 冷月无声 - 博客频道 - CSDN.NET http://blog.csdn.net/jaytalent/article/details/50986402 本文结合一些 ...
- AngularJS依赖注入
文中内容基本上来自<AngularJS权威教程> 一个对象通常有三种方式可以获得对其依赖的控制权: 在内部创建依赖 通过全局变量进行引用 在需要的地方通过参数进行传递 依赖注入是通过第三种 ...
- [ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式
IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架之中以实现对流程的复用,并按照"好莱坞法则"实现应用程序的代码与框架之间的交互.我们可以采用若干设计模式 ...
- php 框架 容器,thinkphp5.1框架容器与依赖注入实例分析
本文实例讲述了thinkphp5.1框架容器与依赖注入.分享给大家供大家参考,具体如下: 容器----/thinkphp/library/think/Container.php 依赖注入:将对象类型的 ...
- 【Spring笔记】依赖注入
依赖注入:bean对象的创建依赖于容器.bean对象中的所有属性,由容器来注入. 可分为构造器注入,Set方式注入,拓展方式注入 环境搭建: 实体类: beans.xml 测试类: @Testpubl ...
- 揭开均线系统的神秘面纱_揭开依赖注入的神秘面纱,并通过此快速介绍了解它的实际应用...
揭开均线系统的神秘面纱 by Sankalp Bhatia 通过Sankalp Bhatia 揭开依赖注入的神秘面纱,并通过此快速介绍了解它的实际应用 (Demystify Dependency In ...
最新文章
- Leetcode 15.三数之和 双指针 or 暴力哈希
- 我的XGBoost学习经历及动手实践
- c语言循环控制答案,C语言程序设计 实四 循环控制 答案 《西北民大 电气院》.doc...
- Opera在本博客的发文方法,fedora8下
- flex----导航
- arraylist转int数组_五千字的数组拓展,面试官对我竖起大拇指喊停
- Java一行代码打印当前系统时间
- 百练2810:完美立方
- java基础之java中的基本数据类型
- 定制基元和DTO的(反)序列化和验证
- 伺服电机停的时候会冲一下_造成伺服电机抖动的原因竟然是它!内附解决方法...
- 1.8 编程基础之多维数组 22 神奇的幻方 python
- Native App
- LeetCode —— 980. 不同路径 III(Python)
- 最近一周交易所钱包比特币数量减少18425枚
- 简书文章阅读量之小漏洞
- mysql oracle视频网盘_前端和后端终极学习视频(百度网盘资料)
- winserve2016 万能驱动网卡_windows server 2016 安装网卡驱动
- PR值是什么?pr值的意义
- 如何利用小程序布局社交电商?