前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET Core开发实战(第6课:作用域与对象释放行为)--学习笔记(下)

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

作者头像
郑子铭
发布2021-01-13 15:21:23
4900
发布2021-01-13 15:21:23
举报

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

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

代码语言:javascript
复制
services.AddSingleton<IOrderService>(p => new DisposableOrderService());

启动程序,输出如下:

代码语言:javascript
复制
=======1==========
=======2==========
接口请求处理结束

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

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

代码语言:javascript
复制
services.AddTransient<IOrderService>(p => new DisposableOrderService());

启动程序,输出如下:

代码语言:javascript
复制
=======1==========
DisposableOrderService Disposed:12021664
DisposableOrderService Disposed:32106157
=======2==========
接口请求处理结束
DisposableOrderService Disposed:3165221
DisposableOrderService Disposed:13048313

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

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

代码语言:javascript
复制
var service = new DisposableOrderService();
services.AddSingleton<IOrderService>(service);

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

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

如何识别这个区别呢?

在控制器中注入 IHostApplicationLifetime 接口

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

它有一个方法 StopApplication

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

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

代码语言:javascript
复制
[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;
}

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

代码语言:javascript
复制
var service = new DisposableOrderService();
services.AddSingleton<IOrderService>(service);

启动程序

输入 ?stop=true

代码语言:javascript
复制
https://localhost:5001/weatherforecast?stop=true

输出如下:

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

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

代码语言:javascript
复制
services.AddSingleton<IOrderService, DisposableOrderService>();

启动程序

输入 ?stop=true

代码语言:javascript
复制
https://localhost:5001/weatherforecast?stop=true

输出如下:

代码语言:javascript
复制
Application is shutting down...
接口请求处理结束
DisposableOrderService Disposed:23399238

对象释放,应用程序退出

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

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

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

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

假如把服务注册成瞬时的

代码语言:javascript
复制
services.AddTransient<IOrderService, DisposableOrderService>();

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

代码语言:javascript
复制
var s = app.ApplicationServices.GetService<IOrderService>();

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

调整控制器,不获取 IOrderService

代码语言:javascript
复制
[HttpGet]
public int Get(
    [FromServices]IHostApplicationLifetime hostApplicationLifetime,
    [FromQuery]bool stop = false)
{

    if (stop)
    {
        hostApplicationLifetime.StopApplication();
    }

    return 1;
}

仅仅在根容器获取一次

代码语言:javascript
复制
var s = app.ApplicationServices.GetService<IOrderService>();

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

但实际上当我们退出的时候,会发现确实有一个实例被释放掉了

代码语言:javascript
复制
DisposableOrderService Disposed:7511460

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 06 | 作用域与对象释放行为
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档