asp.net core 3.1學習筆記——作用域與對象的釋放行爲

一、原理和注意事項:

作用域由 IServiceScope 對象承載,對於實現了IDisposable接口類型的對象,容器會去負責對其生命週期的管理,當使用完畢它會去釋放對象;實現IDisposable接口類型對象的釋放特點:

  • DI 只負責釋放由其創建的對象;
  • DI 在容器或子容器釋放時,釋放由其創建的對象實例;

如果對象是由我們自己創建並放到容器裏面,容器不負責釋放該對象;容器的生命週期與其創建的對象的生命週期有對應關係,這裏我們需要以下兩點注意事項:

  • 在根容器不要去創建實現了 IDisposable 的瞬時服務;
  • 避免手動創建對象且將該對象放入容器裏面,應該儘可能的使用容器去管理我們的對象的創建和釋放;

二、代碼示例與測試結果:

首先創建一個 OrderService 的服務,代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace DependencyInjectionScopeAndDisposableDemo.Services
{
    public interface IOrderService
    {

    }

    public class DisposableOrderService : IOrderService, IDisposable
    {
        public void Dispose()
        {
            Console.WriteLine($"DisposableOrderService Disposed:{this.GetHashCode()}");
        }
    }
}

然後在 Startup 的 ConfigureServices 中分別註冊以下服務,測試作用域對象的生命週期和釋放,如下所示:

//1.瞬態
services.AddTransient<IOrderService, DisposableOrderService>();
services.AddTransient<IOrderService>(service => new DisposableOrderService()); //工廠模式註冊;

//2.單例
services.AddSingleton<IOrderService, DisposableOrderService>();
services.AddSingleton<IOrderService>(services => new DisposableOrderService());

//3.作用域
services.AddScoped<IOrderService, DisposableOrderService>();
services.AddScoped<IOrderService>(services => new DisposableOrderService());

//4.自創建方式單例註冊
var service = new DisposableOrderService();
services.AddSingleton<IOrderService>(service);

測試輸出對象的HashCode和該對象的生命週期和釋放行爲,控制器方法如下:

  • 瞬態服務註冊測試:
[HttpGet]
public int Get(
    [FromServices]IOrderService orderService,
    [FromServices]IOrderService orderService2) 
{
    Console.WriteLine("接口請求處理結束");
    return 1;
}

1.瞬態測試輸出結果如下:

接口請求處理結束
DisposableOrderService Disposed:21621962
DisposableOrderService Disposed:29422698

瞬時服務在每一接口調用時都會獲得一個對象,且在接口處理完畢後將其註冊對象服務釋放;
  • 單例服務註冊測試:
2.單例測試,控制器中的請求方法不變(如下3),測試結果如下:

=======1==========
=======2==========
接口請求處理結束

執行順序一樣,但單例模式註冊服務的對象不會被釋放;
  • 作用域服務註冊測試:
[HttpGet]
public int Get(
    [FromServices]IOrderService orderService,
    [FromServices]IOrderService orderService2) 
{
    #region 測試作用域Scope
    Console.WriteLine("=======1==========");
    using (IServiceScope scope = HttpContext.RequestServices.CreateScope())
    {
        //創建作用域子容器
        var service = scope.ServiceProvider.GetService<IOrderService>();
        var service2 = scope.ServiceProvider.GetService<IOrderService>();
    }
    Console.WriteLine("=======2==========");
    #endregion

    Console.WriteLine("接口請求處理結束");
    return 1;
}

3.作用域測試輸出結果如下:

=======1==========
DisposableOrderService Disposed:8140213
=======2==========
接口請求處理結束
DisposableOrderService Disposed:21353980

同樣作用域服務註冊還是先執行接口方法,執行完畢再將其對象釋放,但同一個作用域內對象只會創建一次(局部單例模式);
  • 自創建方式單例註冊
4.測試結果如下:

=======1==========
=======2==========
接口請求處理結束

同樣的測試結果,自創建註冊方式,對象不會被其容器所釋放;

以上就是對服務註冊的幾種方式以及對象釋放的生命週期測試結果;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章