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. vue prop 会接收不同的数据类型

    refAge: { type: Number, default: 0 }, refName: { type: String, default: '' }, hotDataLoading: { type ...

  2. 每天学五分钟 Liunx 100 | 存储篇:磁盘分区

    这一节主要介绍 Liunx 是怎么用磁盘的. 磁盘分区 在 Liunx 中一切皆文件,磁盘在 Liunx 中也是文件,包括 /dev/hd[a-d](以 IDE 为接口) 和 /dev/sd[a-p] ...

  3. 分享一个在线二维码生成器(基于qrcode.js开发)

    一种二维码扫描与生成的工具, 它可生成个性化二维码, 支持文本.网址.图片.短信.电话等格式及主题,提供融合码功能 演示地址 https://qrcode.gitapp.cn 关键代码 var qrc ...

  4. spring启动流程 (1) 流程概览

    本文将通过阅读AnnotationConfigApplicationContext源码,分析Spring启动流程. 创建AnnotationConfigApplicationContext Annot ...

  5. [转帖]直接内存监控不准确,netty玩了什么花?

    https://segmentfault.com/a/1190000044509636     是挺久没有"宠爱"我们netty小婊贝了,最近又开始搞事了. 于是,趁机探究了下MX ...

  6. 鲲鹏920上面 Docker 部署 clickhouse 的方式方法

    鲲鹏920上面 Docker 部署 clickhouse 的方式方法 背景 最近有一套鲲鹏920的测试环境, 研发同事想纯Dcoker部署一套环境. 其中就包括了 Clickhouse 之前发现Cli ...

  7. [转帖]linux 查看CPU 内存的信息

    https://bbs.huaweicloud.com/blogs/302929   [摘要] ECS信息规格:2vCPUs | 4GiB | kc1.large.2镜像:openEuler 20.0 ...

  8. MySQL备份恢复简单处理方法

    客户备份恢复的脚本处理简要如下: 首先登陆mysql服务器 方法如下: mysql -uroot -p 输入密码即可登陆 然后需要创建一个数据库, 个人感觉同名恢复最容易出问题 create data ...

  9. Concat、Push、Spread syntax性能差异对比

    今天在力扣上做了一道数组扁平化的题,按理来说,应该熟能生巧了,但是在使用concat时候超出了时间限制,使用push可以通过,代码如下: /** * @describe 使用concat,超出时间限制 ...

  10. vite构建打包产物

    构建打包产物 build: { assetsInlineLimit: 10240, //静态资源(不会包含js,css)不超过10kb 转化为 base64 [不好含css js] outDir: & ...