06 | 作用域与对象释放行为

接下来,把服务切换为单例模式,通过工厂的方式

services.AddSingleton<IOrderService>(p => new DisposableOrderService());

启动程序,输出如下:

=======1==========
=======2==========
接口请求处理结束

可以看到代码实际上不会被释放

如果切换为瞬时模式,通过工厂的方式

services.AddTransient<IOrderService>(p => new DisposableOrderService());

启动程序,输出如下:

=======1==========
DisposableOrderService Disposed:12021664
=======2==========
接口请求处理结束
DisposableOrderService Disposed:3165221
DisposableOrderService Disposed:13048313

这里可以看到,获取三个服务并且释放掉

接下来把服务调整为自己创建,并注册进去

var service = new DisposableOrderService();
services.AddSingleton<IOrderService>(service);

同样我们也不会得到释放的输出

也就是说,通过这种方式注册,容器不会管理对象的生命周期

如何识别这个区别呢?

在控制器中注入 IHostApplicationLifetime 接口

这个接口的作用是用来管理整个应用程序的生命周期

它有一个方法 StopApplication

也就是说它可以把整个应用程序关掉

接着,通过手工关掉的方式看一下应用程序关闭时会不会把单例对象释放掉

[HttpGet]
public int Get([FromServices] IOrderService orderService,
[FromServices] IOrderService orderService2,
[FromServices]IHostApplicationLifetime hostApplicationLifetime,
[FromQuery]bool stop = false)
{
Console.WriteLine("=======1==========");
// HttpContext.RequestServices 是当前请求的一个根容器,应用程序根容器的一个子容器,每个请求会创建一个容器
using (IServiceScope scope = HttpContext.RequestServices.CreateScope())
{
// 在这个子容器下面再创建一个子容器来获取服务
var service = scope.ServiceProvider.GetService<IOrderService>();
var service2 = scope.ServiceProvider.GetService<IOrderService>();
}
Console.WriteLine("=======2=========="); if (stop)
{
hostApplicationLifetime.StopApplication();
} Console.WriteLine("接口请求处理结束"); return 1;
}

首先用自己创建对象的方式

var service = new DisposableOrderService();
services.AddSingleton<IOrderService>(service);

启动程序

输入 ?stop=true

https://localhost:5001/weatherforecast?stop=true

输出如下:

...
DependencyInjectionScopeAndDisposableDemo.exe (进程 16884)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

如果单例由容器来管理,切换回普通注册方式

services.AddSingleton<IOrderService, DisposableOrderService>();

启动程序

输入 ?stop=true

https://localhost:5001/weatherforecast?stop=true

输出如下:

Application is shutting down...
接口请求处理结束
DisposableOrderService Disposed:23399238

对象释放,应用程序退出

这里说明单例的服务都是注册在根容器里面

根容器的释放意味着需要在整个应用程序退出时释放

这个时候它会释放自己所管理的所有的 IDisposable 的对象

这里面有一个非常需要注意的坑:

假如把服务注册成瞬时的

services.AddTransient<IOrderService, DisposableOrderService>();

然后又在根容器里面去获取这个对象

var s = app.ApplicationServices.GetService<IOrderService>();

这意味着在根容器去持续的创建 IOrderService,但是由于根容器只会在应用程序整个退出时回收,也就意味着这些对象会一直积累在应用程序内

调整控制器,不获取 IOrderService

[HttpGet]
public int Get(
[FromServices]IHostApplicationLifetime hostApplicationLifetime,
[FromQuery]bool stop = false)
{ if (stop)
{
hostApplicationLifetime.StopApplication();
} return 1;
}

仅仅在根容器获取一次

var s = app.ApplicationServices.GetService<IOrderService>();

这样运行起来,每次请求(点击刷新)的话,整个输出是不会有内容的,因为我们没有在子容器里面去获取对象

也就是说,实现了 IDisposable 接口的服务,如果时注册瞬时的,又在根容器去做操作,它会一直保持到应用程序退出的时候,才能够被回收掉

GitHub源码链接:

https://github.com/MingsonZheng/DotNetCoreDevelopmentActualCombat/tree/main/DependencyInjectionScopeAndDisposableDemo

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

.NET Core开发实战(第6课:作用域与对象释放行为)--学习笔记(下)的更多相关文章

  1. 《Flask Web开发实战:入门、进阶与原理解析》 学习笔记

    一个视图函数可以绑定多个 URL 为了让互联网上的人都可以访问,需要安装程序的服务器有公网ip 如果过度使用扩展,在不需要 的地方引人,那么相应也会导致代码不容易维护 ,应该尽量从实际需求出发,只在需 ...

  2. 2月送书福利:ASP.NET Core开发实战

    大家都知道我有一个公众号“恰童鞋骚年”,在公众号2020年第一天发布的推文<2020年,请让我重新介绍我自己>中,我曾说到我会在2020年中每个月为所有关注“恰童鞋骚年”公众号的童鞋们送一 ...

  3. [ASP.NET Core开发实战]开篇词

    前言 本系列课程文章主要是学习官方文档,再输出自己学习心得,希望对你有所帮助. 课程大纲 本系列课程主要分为三个部分:基础篇.实战篇和部署篇. 希望通过本系列课程,能让大家初步掌握使用ASP.NET ...

  4. .NET Core开发实战(第11课:文件配置提供程序)--学习笔记

    11 | 文件配置提供程序:自由选择配置的格式 文件配置提供程序 Microsoft.Extensions.Configuration.Ini Microsoft.Extensions.Configu ...

  5. [ASP.NET Core开发实战]基础篇02 依赖注入

    ASP.NET Core的底层机制之一是依赖注入(DI)设计模式,因此要好好掌握依赖注入的用法. 什么是依赖注入 我们看一下下面的例子: public class MyDependency { pub ...

  6. 2、SpringBoot接口Http协议开发实战8节课(1-6)

    1.SpringBoot2.xHTTP请求配置讲解 简介:SpringBoot2.xHTTP请求注解讲解和简化注解配置技巧 1.@RestController and @RequestMapping是 ...

  7. [ASP.NET Core开发实战]基础篇03 中间件

    什么是中间件 中间件是一种装配到应用管道,以处理请求和响应的组件.每个中间件: 选择是否将请求传递到管道中的下一个中间件. 可在管道中的下一个中间件前后执行. ASP.NET Core请求管道包含一系 ...

  8. [ASP.NET Core开发实战]基础篇01 Startup

    Startup,顾名思义,就是启动类,用于配置ASP.NET Core应用的服务和请求管道. Startup有两个主要作用: 通过ConfigureServices方法配置应用的服务.服务是一个提供应 ...

  9. 2、SpringBoot接口Http协议开发实战8节课(7-8)

    7.SpringBoot2.x文件上传实战 简介:讲解HTML页面文件上传和后端处理实战 1.讲解springboot文件上传 MultipartFile file,源自SpringMVC 1)静态页 ...

  10. [ASP.NET Core开发实战]基础篇06 配置

    配置,是应用程序很重要的组成部分,常常用于提供信息,像第三方应用登录钥匙.上传格式与大小限制等等. ASP.NET Core提供一系列配置提供程序读取配置文件或配置项信息. ASP.NET Core项 ...

随机推荐

  1. js根据对象数组中某一属性值,合并相同项,并对某一属性累加处理

    https://www.cnblogs.com/mahao1993/p/13491430.html

  2. P4913【黄】

    这题好像可以用线段树什么的高级做法来做,但我感觉我这个简单做法不管是时间还是空间都和那些复杂的做法差不了太多.重点是很优雅,思路非常简单,而且代码很短,用OOP思想写成的代码可读性极高,不用注释估计都 ...

  3. python常见面试题讲解(十一)字符串反转-五种解法

    题目描述 写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串.(字符串长度不超过1000) 输入描述: 输入N个字符 输出描述: 输出该字符串反转后的字符串 示例1 输入 abcd 输出 d ...

  4. 搬运 |(有刀🔪慎入)kwdnx、谷雨、更漏与我

    本打算把文案投到官微,但官微说文案太长了,只能放删减版: 那就把文案放博客上吧 写于 癸卯年 戊午月 己亥日. 四年前的冬天我们初见,大家都是青涩的未成年人:在少年班团建的喧闹中,谷雨谈论高数竞赛,k ...

  5. 【架构师视角系列】Apollo配置中心之Client端(二)

    原创文章,转载请标注.https://www.cnblogs.com/boycelee/p/17978027 目录 声明 配置中心系列文章 一.客户端架构 1.Config Service职责 (1) ...

  6. Verilog仿真实践

    Verilog必须掌握 逻辑仿真工具(VCS)和逻辑综合工具(DC) AndOR module AndOr( output X,Y, input A,B,C ); // A B进行按位与运算 assi ...

  7. [转帖]Oracle进程中的 LOCAL=NO 和 LOCAL=YES

    https://www.cnblogs.com/wjoyxt/p/3780860.html 我们在服务器上用sqlplus 连接数据库,在查看进程,会多出一条记录: oracle 16007 1600 ...

  8. Linux用户以及ssh安全相关设置

    Linux用户相关操作 摘要 最近重保, 需要进行网络安全防护. 部分同事处理过程总是顺序有一些不太对的情况. 同时发现自对Linux用户设置也存在很多不清不楚的地方 所以趁着周末学习和总结一下. 用 ...

  9. NutUI 4.0 正式发布!

    作者: 京东零售 NutUI NutUI 4.0 Github 地址:github.com/jdf2e/nutui NutUI 4.0 官网:nutui.jd.com 前言 技术日异月新.发展创新.持 ...

  10. Loguru:Python 日志终极解决方案

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 日志的重要性 日志的作用非常重要,日志可以记录用户的操作.程序的异常,还可以为数据分析提供依据,日志的存在意义就是为了能够在程序 ...