Core官方DI解析(5)-ServiceProviderEngine

来源:https://www.cnblogs.com/yan7/archive/2018/11/30/10042170.html
-Advertisement-
Play Games

最後來看看前面一直說的 Engine(工作引擎) ,工作引擎介面是 在`ServiceProvider IServiceProviderEngine`介面和其實現類的整體結構 IServiceProviderEngine類型繼承關係 繼承了 介面,也就是說工作引擎也具有 GetService() 方 ...


最後來看看前面一直說的Engine(工作引擎),工作引擎介面是IServiceProviderEngineServiceProvider的構造函數中看到了根據指定的Mode創建了不同的實現類,下麵先來看一下IServiceProviderEngine介面和其實現類的整體結構

IServiceProviderEngine類型繼承關係

internal interface IServiceProviderEngine : IDisposable, IServiceProvider
 {
      IServiceScope RootScope { get; }
 }
`IServiceProvderEngine這個介面`繼承了`IServiceProvider`介面,也就是說工作引擎也具有**GetService()**方法,在此介面中具有一個`IServiceScope`類型的**RootScope**,而這個屬性則代表是**根容器**

`IServiceScope`代表一個容器介面,這個介面中具有一個`IServiceProvider`類型的屬性,返回真正表示容器的一個`IServiceProvider`類型            
public interface IServiceScope : IDisposable
{
   /// <summary>
   /// The <see cref="System.IServiceProvider"/> used to resolve dependencies from the scope.
   /// </summary>
   IServiceProvider ServiceProvider { get; }
}   

IServiceProviderEngine整體結構

IServiceProviderEngine

  • ServiceProviderEngine
    • CompiledServiceProviderEngine
      • DynamicServiceProviderEngine
    • RuntimeServiceProviderEngine
    • ILEmitServiceProviderEngine
    • ExpressionsServiceProviderEngine
上面是目前整個引擎結構,但是前面說過目前只用到了`DynamicServiceProviderEngine`,但是我們看整個類型會看到其實在這幾個派生類型中只有一個實現方法`RealizeService(ServiceCallSite callSite)`,而整體結構都是在基類`ServiceProviderEngine`類型中,下麵來看看這個基類類型

ServiceProviderEngine

`ServiceProviderEngine`類型是整個結構的核心類型,但是這個類也是一個很簡單的類,這個類只是調用`CallSiteFactory`和`CallSiteRuntimeResolver`,由下圖可以看到這個類型是一個抽象類,並且實現了`IServiceProviderEngine`和`IServiceScopeFactory`介面介面            

`IServiceScopeFactory`這個介面提供了一個創建子容器方法我們已知道`IServiceProviderEngine`介面*繼承*了`IServiceProvider`介面,那麼也就是說在`ServiceProviderEngine`已經具備以下兩個功能 

1.獲取服務實例對象

2.創建子容器

internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory{}


//      創建子容器介面
public interface IServiceScopeFactory
{
     //     
     IServiceScope CreateScope();
}

下麵首先來看一下此類中擁有的欄位+屬性,這些屬性都是在構造器中進行了實例化

  • _callback:

    這個欄位就是頂級容器時檢查scoped生命周期的訪問者對象,這個從ServiceProvider類中時進行傳入的,在這裡並不細講這個類型

  • RealizedServices:

    這個屬性是緩存根據容器獲取服務實例對象委托,其中Key為ServiceType

  • _createServiceAccessor:

    這是一個根據類型獲取一個根據容器獲取服務實例對象的委托,可以看到使用了一個CreateServiceAccessor()進行賦值,CreateServiceAccessor()是此類型的一個核心方法,下麵介紹

  • CallSiteFactory:

    ServiceCallSite工廠類型,在構造器中實例化,可以看到實例化時將serviceDescriptors進行傳入,並且可以看到在構造器中向此實例對象中添加了一個IServiceProviderIServiceScopeFactory

  • RuntimeResolver:

    這個屬性是是獲取服務實例的訪問者對象,可以看到在構造器中進行傳入

  • Root:

    Root代表是一個頂級容器ServiceProviderEngineScope類型則是一個具體的容器類型,這個類型中緩存了所有的具體服務實例對象,這個類型實現了IServiceScope介面,從下麵代碼可以看到RootScope其實就是直接返回了Root屬性

  • RootScope:

    這也是一個根容器實例對象,直接返回的Root屬性

//      頂級容器時scoped生命周期實例檢查策略   
private readonly IServiceProviderEngineCallback _callback;
//      根據類型創建構建服務的委托
private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor;
//      此實例是否被銷毀
private bool _disposed;

//      緩存根據容器獲取服務實例的委托,  Key為註冊類型
internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; }

 //     CallSite工廠類屬性,此類型用於根據指定實例化方式來創建對應的CallSite
internal CallSiteFactory CallSiteFactory { get; }
//      訪問者對象,此對象對進行實例和緩存具體真正的對象
protected CallSiteRuntimeResolver RuntimeResolver { get; }

//      根容器實例屬性
public ServiceProviderEngineScope Root { get; }
//      根容器實例屬性
public IServiceScope RootScope => Root;

//      構造器
protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
     _createServiceAccessor = CreateServiceAccessor;
     _callback = callback;
     //      實例化根容器
     Root = new ServiceProviderEngineScope(this);
     //      實例化 CallSite對象訪問者對象
     RuntimeResolver = new CallSiteRuntimeResolver();

     //      實例化CallSiteFactory類型對象
     CallSiteFactory = new CallSiteFactory(serviceDescriptors);
     CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
     //      緩存一個ServiceScopeFactoryCallSite服務,相當於緩存一個ServiceProviderEngine,根據此對象進行創建子容器
     CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
     //     緩存實例化對象的工廠
     RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
}
`ServiceProviderEngine`類型中方法只有**GetService()**,**CreateScope()**,**CreateServiceAccessor()**,**Dispose()**和一個抽象方法**RealizeService()**,其中幾個派生類中都只是實現了**RealizeService()**,這個一會再看,下麵來看看`ServiceProviderEngine`類中的這幾個方法
  • RealizeService:

    這個方法由派生類繼承,由指定的ServiceCallSite緩存並獲取 服務實例的委托

  • GetService:

    這個方法獲取服務實例對象,可以看到具有兩個此方法,並且第一個調用了第二個,並將頂級容器Root進行了傳入,而在第二個方法中,獲取並添加**_createServiceAccessor**委托,然後調用此委托進行獲取服務實例

  • CreateScope:

    這個方法是創建一個子容器對象,在這個方法中可以看到直接 new 了一個容器對象,並將當前對象進行了傳入。從此可以得知為什麼所有容器共用頂級容器的服務註冊了

  • Dispose:

    清除當前對象,並清除頂級容器

  • CreateServiceAccessor:

    這個方法可以看到根據ServiceType進行獲取指定ServiceCallSite,然後再調用派生類實現的RealizeService()進行返回

//      抽象類型,子類實現
protected abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);

public object GetService(Type serviceType) => GetService(serviceType, Root);

internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
{
     if (_disposed)
        ThrowHelper.ThrowObjectDisposedException();
     //      添加並獲取根據容器對象實例化對象的方法,其方法由子類進行重寫
     var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor);
     //      驗證是否允許進行實例化對象
     _callback?.OnResolve(serviceType, serviceProviderEngineScope);
     return realizedService.Invoke(serviceProviderEngineScope);
}
public void Dispose()
{
     _disposed = true;
     Root.Dispose();
}
//      實例化的子容器
public IServiceScope CreateScope()
{
     if (_disposed)
          ThrowHelper.ThrowObjectDisposedException();
     return new ServiceProviderEngineScope(this);
}
private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
{
     //      根據基類類型獲取對應的CallSite
     var callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
     if (callSite != null)
     {
          //  緩存當前註冊
          _callback?.OnCreate(callSite);
          return RealizeService(callSite);
     }
     return _ => null;
}

DynamicServiceProviderEngine和CompiledServiceProviderEngine

下麵來看一下`DynamicServiceProviderEngine`和`CompiledServiceProviderEngine`這兩個派生類型,從上面繼承關係可以看到這兩個派生類型是一個繼承關係 `DynamicServiceProviderEngine`繼承於`CompiledServiceProviderEngine`.
internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine{}

​在這兩個派生類型中都只是實現了基類的RealizeService(),下麵先來看看CompiledServiceProviderEngine類的實現

可以看到CompiledServiceProviderEngine類中具有一個ExpressionResolverBuilder對象,這個類是使用表達式樹生成結構,這個實例在構造函數進行創建,並且將CallSiteRuntimeResolver對象,本對象和頂級容器進行了傳入,可以看到在重寫的方法中是調用了ExpressionResolverBuilder對象的Build(),這個方法會生成一個Func<ServiceProviderEngineScope,Object>委托,然後緩存此委托,

註:ExpressionResolverBuilder這個類挺複雜,我也沒看懂,所以在此不介紹,有興趣的可以直接看源碼

internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
{
    //      表達式樹生成對象
     public ExpressionResolverBuilder ExpressionResolverBuilder { get; }
     
     //     構造函數
     public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
        => ExpressionResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
     
     //     重寫RealizeService方法
     protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
     {
          //      使用表達式樹進行創建一個Func<ServiceProviderEngineScope,Object>委托
          var realizedService = ExpressionResolverBuilder.Build(callSite);
          //      直接將表達式生成的委托進行替換之前的緩存
          RealizedServices[callSite.ServiceType] = realizedService;
          return realizedService;
     }
}
而在`RuntimeServiceProviderEngine`類中,則只是實現了**RealizeService()**,從下麵代碼可以看出在第一次調用時是直接調用`CallSiteRuntimeResolver`這個訪問者獲取的實例數據,而在第二次才調用的基類,也就是`CompiledServiceProviderEngine`進行了緩存,但是至於為什麼這樣乾,我沒有弄清。。。
internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
     public DynamicServiceProviderEngine(
     IEnumerable<ServiceDescriptor> serviceDescriptors, 
     IServiceProviderEngineCallback callback) 
     : base(serviceDescriptors, callback)
     {
     }

     protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
     {
          var callCount = 0;
          return scope =>
          {
               if (Interlocked.Increment(ref callCount) == 2)
               {
                    //      如果當前是第二次調用,則調用父級進行緩存
                    Task.Run(() => base.RealizeService(callSite));
               }
               //      調用訪問者進行根據當前容器和CallSite進行實例化服務對象
               return RuntimeResolver.Resolve(callSite, scope);
          };
     }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 摘要:本文主要對Java這門編程語言進行簡單的介紹。 Java簡介 說明 Java語言歷時十多年,已發展成為人類電腦史上影響深遠的編程語言,從某種程度上來看,它甚至超出了編程語言的範疇,成為一種開發平臺,一種開發規範。Java語言所崇尚的開源、自由等精神,吸引了全世界無數優秀的程式員。事實是,從人 ...
  • 1.管道 進程間通信(IPC)方式二:管道(不推薦使用,瞭解即可),埠易導致數據不安全的情況出現。 2.共用數據 進程之間數據共用的模塊之一Manager模塊(少用): 進程間數據是獨立的,可以藉助於隊列或管道實現通信,二者都是基於消息傳遞的雖然進程間數據獨立,但可以通過Manager實現數據共用 ...
  • 一、input()函數 在 Python 中,使用內置函數 input()可以接收用戶的鍵盤輸入。 input()函數的基本用法如 下: 其中,variable 為保存輸入結果的變數,雙引號內的文字用於提示要輸入的內容。 二、print()函數預設的情況下,在Python中,使用內置的print() ...
  • 一:EL表達式 1.概述:在jsp開發中,為了獲取Servlet域對象中存儲的數據,經常要寫很多java代碼,這樣的做法會使JSP頁面混亂,難以維護,為此,在JSP2.0規範中提供了EL表達式。它是Expression Language的縮寫。 2.語法:${表達式} 2.1內置對象: 2.1.1獲 ...
  • 一、引言 官網文檔:http://www.mybatis.org/generator/index.html 通過使用官方提供的mapper自動生成工具,mybatis-generator-core-1.3.2來自動生成po類和mapper映射文件。 作用:mybatis官方提供逆向工程,可以使用它通 ...
  • 1. 什麼是列表 定義: 能裝對象的對象 在python中使用 [] 來描述列表, 內部元素用逗號隔開. 對數據類型沒有要求 列表存在索引和切片. 和字元串是一樣的. 2. 相關的增刪改查操作 添加: 1. append() 追加 2. insert(位置, 元素) 插入指定元素到指定位置 刪除: ...
  • 題意 "題目鏈接" Sol 神仙題Orzzzz 題目可以轉化為從$\leqslant M$的質數中選出$N$個$xor$和為$0$的方案數 這樣就好做多了 設$f(x) = [x \text{是質數}]$ $n$次異或FWT即可 快速冪優化一下,中間不用IFWT,最後轉一次就行(~~然而並不知道為什 ...
  • 1.進程同步/串列(鎖) 進程之間數據不共用,但共用同一套文件系統,所以訪問同一個文件,或同一個列印終端,沒有問題,但共用帶來的是競爭容易錯亂,如搶票時。這就需讓進程一個個的進去保證數據安全,也就是加鎖處理,Lock 併發,效率高,但是競爭同一個文件時,導致數據混亂 加鎖,由併發改成了串列,犧牲了運 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...