從上篇內容不如題的文章《.net core 併發下的執行緒安全問題》擴充套件認識.net core註入中的三種樣式:Singleton、Scoped 和 Transient
我們都知道在 Startup 的 ConfigureServices 可以註入我們想要的服務,那麼在註入的時候有三種樣式可以選擇,那麼我們在什麼時候選擇什麼樣的樣式呢?
在講註入樣式之前,我覺得很有必要瞭解服務生存期的概念!
服務生存期:ASP.NET Core 提供了一個內建的服務容器 IServiceProvider 負責管理服務的生命週期,從被依賴註入容器建立開始(就是將服務註入到你要使用的類的建構式中),然後框架負責建立依賴關係的實體,併在不再需要時對其進行處理(就是說等我們呼叫完服務時,容器會自己去對註入的服務進行釋放)。
IServiceProvider 怎麼負責的呢?
// System.IServiceProvider
using System;
public interface IServiceProvider
{
object GetService(Type serviceType);
}
可以看出是透過 GetService 此介面的方法獲取提供服務的物件。那再走深一點找找,我們看看 程式集 Microsoft.Extensions.DependencyInjection 是怎麼提供這個容器的
//Microsoft.Extensions.DependencyInjection.IServiceProviderFactory
using Microsoft.Extensions.DependencyInjection;
using System;
public interface IServiceProviderFactory
{
TContainerBuilder CreateBuilder(IServiceCollection services);
IServiceProvider CreateServiceProvider(TContainerBuilder containerBuilder);
}
看到上面的 IServiceProviderFactory 介面是不是很熟悉了,這個容器裡會有一個 IServiceCollection(服務集合),那服務怎麼加進入(實現)的呢
//Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions
using System;
private static IServiceCollection Add(IServiceCollection collection, Type serviceType, Type implementationType, ServiceLifetime lifetime)
{
ServiceDescriptor item = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(item);
return collection;
}
到這裡,已經很清楚了,也已經接近我們今天的主題了,直接來吧
// Microsoft.Extensions.DependencyInjection.ServiceLifetime
public enum ServiceLifetime
{
Singleton,
Scoped,
Transient
}
上面的列舉裡面就是提供了 Singleton、Scoped 和 Transient 三種樣式。去 微軟的檔案 裡面看看,先瞭解一下這三種樣式,在 ServiceCollectionServiceExtensions 就只有3個方法(有多載喲)
從原始碼裡面絕對可以想到,這3個方法是繼承 IServiceCollection。好了,說說這三種樣式先,畢竟實現我們不是很關心(關心就看檔案看原始碼)
(1)Singleton 單一實體樣式:單一實體物件對每個物件和每個請求都是相同的,可以說是不同客戶端不同請求都是相同的。
(2)Transient 暫時性樣式:暫時性物件始終不同,無論是不是同一個請求(同一個請求裡的不同服務)同一個客戶端,每次都是建立新的實體。
(3)Scoped 作用域樣式:作用域物件在一個客戶端請求中是相同的,但在多個客戶端請求中是不同的。(這句是檔案的原話,我覺得描述的很清晰)
什麼時候用哪種樣式?這個不大好說(希望這個可以成為討論點)
比如一下吧:
1、日誌記錄器可以實現為單例,因為在整個生命週期內都可以只使用一個實體;
2、資料庫訪問背景關係(DbContext)選擇 Scoped 的應該是最佳候選,因為 services.AddDbContext 預設就是 Scoped(哈哈哈);
3、如果需要利用深度依賴關係圖(a deep dependency graph)建立惟一物件,則可以考慮將該物件註冊為 transient 。
還有看看別人怎麼說(對Scoped的描述,在理解上可能不大一樣,見仁見智了老鐵)
還有一個 stackoverflow 的
按別人的經驗,可以作為參考參考:
怎麼驗證?請用 官方例子 執行一下看結果:
瀏覽器第一個tab頁面(第一個請求,可以認為是一個客戶端):
瀏覽器第二個tab頁面(第二個請求,可以認為是另一個客戶端):
看上面的結果就不多說了。
這篇擴充套件認識寫得還蠻有意思的,尤其是在找這三種樣式的使用場景,雖然自己有點見解,但絕對不完整。如更好的見解,很希望能一起分享一下。
下一篇的擴充套件好像要回到源頭,擼擼 .net core 的註入了,哈哈哈……
朋友會在“發現-看一看”看到你“在看”的內容