.NET Core 3.0之深入源码理解HttpClientFactory(一)
寫在前面
創建HttpClient實例的時候,在內部會創建HttpMessageHandler鏈,我們知道HttpMessageHandler是負責建立連接的抽象處理程序,所以HttpClient的維護實際上就是維護HttpMessageHandler的使用,釋放HttpClient并不會及時釋放連接,而通常情況下一般是創建全局使用的HttpClient實例,以減少重復連接的次數。當然這種方式所帶來的的弊端也是顯而易見的,因為當前的HttpClient實例所指向的服務器發生問題或者DNS發生變更,那么該實例是無法做到自動更新指向的。
以下為運行其流程圖:
HttpClientFactory自.NET Core 2.1引入,可以認為它是一個配置和創建HttpClient的中心化,.NET Core通過引入HttpClientFactory用于自動化維護HttpMessageHandler池及其生命周期,避免在手動管理 HttpClient生存期時出現的常見 DNS 問題。在默認情況下MessageHandler的活躍狀態是兩分鐘,也就是說,在兩分鐘后,就可以為HttpClient實例重新定位到正確的主機上。
本文的討論思路將從我們能看到的代碼開始一步步深入。
詳細介紹
HttpClientFactory的功能主要位于Microsoft.Extensions.Http包中,它已經默認包含在Microsoft.AspNetCore.App元包中。針對HttpClientFactory的處理涉及到IHttpClientBuilder、IHttpClientFactory、IHttpMessageHandlerFactory、ITypedHttpClientFactory這幾大接口,以下將分別做討論。
services.AddHttpClient()
我們在創建或者配置HttpClient對象的時候,會在ConfigureServices方法中增加services.AddHttpClient(),即可注冊IHttpClientFactory。
這段代碼位于Microsoft.Extensions.DependencyInjection.HttpClientFactoryServiceCollectionExtensions中,它會初始化相關信息并注冊到IServiceCollection中,這些信息包括日志、選項、核心抽象功能、類型客戶端以及其他基礎設施功能。
需要注意的是,在核心抽象功能中,DefaultHttpClientFactory是單例模式的,其所繼承的接口對象的獲取也是單例的,而HttpMessageHandlerBuilder注冊方式確是每一次GetService的時候都會創建一個新的HttpMessageHandlerBuilder實例。
以下為services.AddHttpClient()的源代碼,其中標紅部分為核心抽象功能的注冊:
11:?services.TryAddTransient<HttpMessageHandlerBuilder, DefaultHttpMessageHandlerBuilder>();?12:?services.AddSingleton<DefaultHttpClientFactory>();?13:?services.TryAddSingleton<IHttpClientFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());?14:?services.TryAddSingleton<IHttpMessageHandlerFactory>(serviceProvider => serviceProvider.GetRequiredService<DefaultHttpClientFactory>());
DefaultHttpClientFactory
DefaultHttpClientFactory是一個用internal修飾的類,意味著該類只能在在其內部使用。它繼承了IHttpClientFactory、IHttpMessageHandlerFactory這兩個接口。由此可見,DefaultHttpClientFactory實例的創建被拆成了兩種行為。
IHttpClientFactory的定位是一個抽象工廠,可以為指定名稱的HttpClient實例創建自定義配置,它只有一個方法,HttpClient CreateClient(string name)。
IHttpMessageHandlerFactory的定位也是一個抽象工廠,它為指定名稱的HttpMessageHandler實例創建自定義配置,它只有一個方法,HttpMessageHandler CreateHandler(string name)。
我們先看一下這兩個方法的實現,會覺得很有意思
可以看到,我們通過名稱查找HttpClient對象的時候,也會依照該名稱以GetOrAdd方式去查找相應的HttpMessageHandler對象,也就說HttpClient對象和HttpMessageHandler對象可以通過名稱關聯起來。
需要注意的時候在調用CreateHandler方法的時候會調用StartHandlerEntryTimer方法,這個方法是干嘛的呢,他維護著定時器。該方法位于Microsoft.Extensions.Http.ActiveHandlerTrackingEntry中,我們將此類視為是一個不可變的(當然,其內部的定時器是變化的),為“到期”池創建一個可以顯著簡化線程需求的新對象。
除了這兩個方法外,我們要需要注意DefaultHttpClientFactory對HttpMessageHandler的管理功能。DefaultHttpClientFactory內部維護者一個定時器和兩個HttpMessageHandler對象集合,這兩個集合分別是ActiveHandler和ExpiredHandler。內部定時器會定期從ExpiredHandler集合中掃描并清理無效的 HttpMessageHandler對象。
ActiveHandler集合的增加是在調用CreateHandler方法時增加的,其移除是在回調的時候移除,這個移除入口也只有這一處。
ExpiredHandler集合的增加也是在調用CreateHandler方法時,通過內部的一個回調機制增加的,其移除通過定時器定期掃描來實現的。這處需要注意的是,ExpiredHandlerTrackingEntry這個類中有一個屬性,代碼如下:
通過WeakReference 類型的變量來標識該HttpMessageHandler對象是否應該被從集合中移除。
定時器一般是個比較消耗資源,而且一旦用不好,就會引發線程問題,DefaultHttpClientFactory在處理定時器的時候,首先通過停止所有掛起的計時器,在清除后如果還需要繼續處理無效HttpMessageHandler對象,將會重新啟動計時器,雖然看似多余了點,但是比通過鎖定整個清理機制來確定是否阻塞清理任何并啟動定時器要好多了。
? 以下為這兩個集合的處理示意圖:
總結
以上是生活随笔為你收集整理的.NET Core 3.0之深入源码理解HttpClientFactory(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Azure云原生构建博客是怎样一种体
- 下一篇: WTM 构建DotNetCore开源生