日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

各层作用_终于弄明白了 Singleton,Transient,Scoped 的作用域是如何实现的

發布時間:2024/9/27 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 各层作用_终于弄明白了 Singleton,Transient,Scoped 的作用域是如何实现的 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:背景

1. 講故事

前幾天有位朋友讓我有時間分析一下 aspnetcore 中為什么向 ServiceCollection 中注入的 Class 可以做到 Singleton,Transient,Scoped,挺有意思,這篇就來聊一聊這一話題,自從 core 中有了 ServiceCollection, 再加上流行的 DDD 模式,相信很多朋友的項目中很少能看到 new 了,好歹 spring 十幾年前就是這么干的。

二:Singleton,Transient,Scoped 基本用法

分析源碼之前,我覺得有必要先介紹一下它們的玩法,為方便演示,我這里就新建一個 webapi 項目,定義一個 interface 和 concrete ,代碼如下:

public class OrderService : IOrderService
{
private string guid;

public OrderService(){
guid = $"時間:{DateTime.Now}, guid={ Guid.NewGuid()}";
}

public override string ToString(){
return guid;
}
}

public interface IOrderService
{
}

1. AddSingleton

正如名字所示它可以在你的進程中保持著一個實例,也就是說僅有一次實例化,不信的話代碼演示一下哈。


public class Startup
{
public void ConfigureServices(IServiceCollection services){
services.AddControllers();

services.AddSingleton();
}
}
[ApiController]
[Route("[controller]")]public class WeatherForecastController : ControllerBase
{
IOrderService orderService1;
IOrderService orderService2;public WeatherForecastController(IOrderService orderService1, IOrderService orderService2){this.orderService1 = orderService1;this.orderService2 = orderService2;
}
[HttpGet]public string Get(){
Debug.WriteLine($"{this.orderService1}\r\n{this.orderService2} \r\n ------");return "helloworld";
}
}

接著運行起來多次刷新頁面,如下圖:

可以看到,不管你怎么刷新頁面,guid都是一樣,說明確實是單例的。

2. AddScoped

正從名字所述:Scope 就是一個作用域,那在 webapi 或者 mvc 中作用域是多大呢?對的,就是一個請求,當然請求會穿透 Presentation, Application, Repository 等等各層,在穿層的過程中肯定會有同一個類的多次注入,那這些多次注入在這個作用域下維持的就是單例,如下代碼所示:


public void ConfigureServices(IServiceCollection services){
services.AddControllers();

services.AddScoped();
}

運行起來多次刷新頁面,如下圖:

很明顯的看到,每次刷 UI 的時候,guid都會變,而在同一個請求 (scope) 中 guid 是一樣的。

3. AddTransient

前面大家也看到了,要么作用域是整個進程,要么作用域是一個請求,而這里的 Transient 就沒有作用域概念了,注入一次 實例化一次,不信的話上代碼給你看唄。


public void ConfigureServices(IServiceCollection services){
services.AddControllers();

services.AddTransient();
}

從圖中可以看到,注入一次就 new 一次,非常簡單吧,當然了,各有各的應用場景。

之前不清楚的朋友到現在應該也明白了這三種作用域,接下來繼續思考的一個問題就是,這種作用域是如何做到的呢?要想回答這個問題,只能研究源代碼了。

三:源碼分析

aspnetcore 中的 IOC 容器是 ServiceCollection,你可以向 IOC 中注入不同作用域的類,最后生成 provider,如下代碼所示:


var services = new ServiceCollection();

services.AddSingleton();var provider = services.BuildServiceProvider();

1. AddSingleton 的作用域是如何實現的

通常說到單例,大家第一反應就是 static,但是一般 ServiceCollection 中會有成百上千個 AddSingleton 類型,都是靜態變量是不可能的,既然不是 static,那就應該有一個緩存字典什么的,其實還真的有這么一個。

1)RealizedServices 字典

每一個 provider 內部都會有一個 叫做 RealizedServices 的字典,這個 字典 將會在后面充當緩存存在, 如下圖:

從上圖中可以看到,初始化的時候這個字典什么都沒有,接下來執行?var orderService = provider.GetService();?效果如下圖:

可以看到 RealizedServices 中已經有了一個 service 記錄了,接著往下執行?var orderService2 = provider.GetService();,最終會進入到?CallSiteRuntimeResolver.VisitCache?方法判斷實例是否存在,如下圖:

仔細看上面代碼的這句話:?if (!resolvedServices.TryGetValue(callSite.Cache.Key, out obj))?一旦字典存在就直接返回,否則就要執行 new 鏈路,也就是?this.VisitCallSiteMain。

綜合來看,這就是為什么可以單例的原因,如果不明白可以拿 dnspy 仔細琢磨琢磨。。。

2. AddTransient 源碼探究

前面大家也看到了,provider 里面會有一個 DynamicServiceProviderEngine 引擎類,引擎類中用 字典緩存 來解決單例問題,可想而知,AddTransient 內部肯定是沒有字典邏輯的,到底是不是呢?調試一下唄。

和單例一樣,最終解析都是由 CallSiteRuntimeResolver 負責的,AddTransient 內部會走到 VisitDisposeCache 方法,而這里會一直走?this.VisitCallSiteMain(transientCallSite, context)?來進行 實例的 new 操作,還記得單例是怎么做的嗎?它會在這個 VisitCallSiteMain 上包一層 resolvedServices 判斷,? 繼續追一下 VisitCallSiteMain 方法吧,這個方法最終會走 CallSiteKind.Constructor 分支調用你的構造函數,代碼如下:


protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument){
switch (callSite.Kind)
{
case CallSiteKind.Factory:
return this.VisitFactory((FactoryCallSite)callSite, argument);
case CallSiteKind.Constructor:
return this.VisitConstructor((ConstructorCallSite)callSite, argument);
case CallSiteKind.Constant:
return this.VisitConstant((ConstantCallSite)callSite, argument);
case CallSiteKind.IEnumerable:
return this.VisitIEnumerable((IEnumerableCallSite)callSite, argument);
case CallSiteKind.ServiceProvider:
return this.VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
case CallSiteKind.ServiceScopeFactory:
return this.VisitServiceScopeFactory((ServiceScopeFactoryCallSite)callSite, argument);
}
throw new NotSupportedException(string.Format("Call site type {0} is not supported", callSite.GetType()));
}

最終由 VisitConstructor 對我的實例代碼的構造函數進行調用,所以你應該理解了為啥每次注入都會new一次。如下圖:

3. AddScoped 源碼探究

當你明白了 AddSingleton, AddTransient 的原理,我想 Scoped 也是非常容易理解的,肯定是一個 scoped 一個 RealizedServices 對吧,不信的話繼續上代碼哈。


static void Main(string[] args){
var services = new ServiceCollection();

services.AddScoped();var provider = services.BuildServiceProvider();var scoped1 = provider.CreateScope();var scoped2 = provider.CreateScope();while (true)
{var orderService = scoped1.ServiceProvider.GetService();var orderService2 = scoped2.ServiceProvider.GetService();
Console.WriteLine(orderService);
Thread.Sleep(1000);
}
}

然后看一下 scoped1 和 scoped2 是不是都存在獨立的緩存字典。

從圖中可以看到,scoped1 和 scoped2 中的 ResolvedServices 擁有不用的count,也就說明兩者是獨立存在的,相互不影響。

四:總結

很多時候大家都這么習以為常的用著,突然有一天被問起還是有點懵逼的,所以時常多問自己幾個為什么還是很有必要的哈???。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的各层作用_终于弄明白了 Singleton,Transient,Scoped 的作用域是如何实现的的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 性感美女视频一二三 | 欧美性极品 | 日本中文字幕高清 | 好色婷婷 | 九九色九九 | 午夜视频在线观看一区 | 成人公开视频 | 日韩成人在线影院 | 欧美精品一级 | 深爱激情丁香 | 国产亚洲AV无码成人网站在线 | 亚洲快播 | 欧美精品国产一区 | 苍井空张开腿实干12次 | 日日狠狠久久偷偷四色综合免费 | 五月婷婷影院 | 欧美激情第五页 | 欧美成人午夜精品久久久 | 国产粉嫩在线观看 | 99热欧美| 精品少妇爆乳无码av无码专区 | 国产伦精品一区二区三区视频女 | 国产精品无码专区av免费播放 | 成人a站 | 亚洲精品久久久久久久久久久 | 97在线观看 | 中文字幕av在线播放 | 精国产人伦一区二区三区 | 亚洲成人资源 | 全程偷拍露脸中年夫妇 | 亚洲一级二级片 | 少妇熟女一区二区 | 天堂在线一区 | 国产一区二区三区 | 欧美黄片一区 | 国产野外作爱视频播放 | 亚洲国产成人精品视频 | www.自拍偷拍 | 精品久久久中文字幕 | 亚欧精品在线观看 | 午夜网页 | 禁漫天堂黄漫画无遮挡观看 | 欧美日韩不卡一区 | 99免费精品视频 | 精品在线二区 | 婷婷狠狠干 | 久久婷婷国产麻豆91天堂 | 亚洲色图18p | 夜夜小视频 | 亚洲综合五月天婷婷丁香 | www日本在线 | 天天干天天色天天 | 一本色道久久综合亚洲精品图片 | 久久精品www | 久久尤物视频 | 女生扒开尿口让男生桶 | 在线亚洲一区二区 | 国产三级一区 | 久热精品在线观看 | 激情五月深爱五月 | 国产福利第一页 | 日日夜夜欧美 | 久热最新视频 | 爱爱视频天天干 | 欧美激情片在线观看 | av黄在线| 懂色一区二区三区免费观看 | 全国男人天堂网 | 亚洲视频在线视频 | 在线中文字幕一区二区 | 亚洲精品动漫在线观看 | 欧美综合激情网 | 欧美精品二区三区 | 国产精品第一页在线观看 | 性一交一乱一透一a级 | 不卡中文字幕在线 | 一级成人免费视频 | 久久只有这里有精品 | 久久国产精品久久精品国产 | www.xxx.日本| 亚洲一区精品视频在线观看 | 国产成人91 | 新版红楼梦在线高清免费观看 | 亚洲av无一区二区三区怡春院 | 少妇影院在线观看 | 污视频在线免费 | 婷婷综合在线视频 | 色哟哟av | 麻豆 美女 丝袜 人妻 中文 | 午夜免费体验区 | 日本美女高潮 | 欧洲精品一区二区三区久久 | 一本大道东京热无码aⅴ | 在线精品一区二区 | 久久久成人av | 亚洲最大福利网 | 青青艹av | 好爽快一点高潮了 | 操韩国美女 |