天天看點

IoC之AutoFac(三)——生命周期

閱讀目錄

  • ​​一、Autofac中的生命周期相關概念​​
  • ​​二、建立一個新的生命周期範圍​​
  • ​​三、執行個體周期範圍​​
  • 3.1   每個依賴一個執行個體(InstancePerDependency)
  • 3.2  單個執行個體(SingleInstance)
  • 3.3  每個生命周期範圍一個執行個體 (InstancePerLifetimeScope)
  • 3.4  每個比對的生命周期範圍一個執行個體(InstancePerMatchingLifetimeScope)
  • 3.5  每個請求一個執行個體( InstancePerRequest)
  • 3.6  每個 Owned 一個執行個體 ( InstancePerOwned)
  • 3.7 線程範圍通過

一、Autofac中的生命周期相關概念

  服務的生命周期:是服務執行個體在您的應用程式中生存的時間 ,即從原始執行個體化到釋放期間。例如,如果你“建立”了一個實作了​

​IDisposable​

​的對象,然後再調用​

​Dispose()​

​,那麼這個對象的生命周期就是從你執行個體化的時候開始,被釋放時結束(或者垃圾回收,如果你沒有主動處置它)。

  服務範圍:應用程式中可以與其他使用該服務的元件共享該服務的區域。例如,在你的應用程式中你可能有一個全局靜态的單例 - 全局對象執行個體的“範圍”将是整個應用程式。另一方面,您可以在使用全局單例的for循環中建立局部變量 - 局部變量的範圍比全局範圍小得多。

​  Autofac​

​中的生命周期概念:結合了這兩個概念。生命周期的範圍等同于您的應用程式中的一個工作單元。在解析服務問題時,​

​Autofac​

​跟蹤已解析的一次性(​

​IDisposable​

​)元件,在工作單元結束時,您将釋放關聯的生命周期範圍(scope),​

​Autofac​

​将自動清理/處理已解析的服務。

  生命周期管理的兩件重要的事情就是共享和清理。

我們來看一個Web應用程式作為更具體的例子來說明生命周期範圍的使用。 假設你有以下情況:

你有一個全局的單例日志記錄服務。
 兩個并發請求進入Web應用程式。
 每個請求都是一個邏輯的“工作單元”,每個請求都需要自己的訂單處理服務。
 每個訂單處理服務都需要将日資訊記錄到日志服務中。      

在這種情況下,您将擁有包含單例記錄服務的根生存期範圍,并且每個請求都有一個子生命周期範圍,每個範圍都有自己的訂單處理服務:

+---------------------------------------------------+
|                 Autofac Container                 |
|                Root Lifetime Scope                |
|                                                   |
|                  Logging Service                  |
|            (     在所有請求中共享        )        |
|                                                   |
| +----------------------+ +----------------------+ |
| |  First Request Scope | | Second Request Scope | |
| |                      | |                      | |
| |   Order Processor    | |   Order Processor    | |
| +----------------------+ +----------------------+ |
+---------------------------------------------------+      

When each request ends, the request lifetime scope ends and the respective order processor gets disposed. The logging service, as a singleton, stays alive for sharing by future requests. 

當每個請求結束時,請求生命周期範圍(scope)被處理,相應的訂單處理服務被銷毀。 日志記錄服務作為一個單例對象,在将來的請求中保持共享。

二、建立一個新的生命周期範圍

您可以通過在任何現有生命周期作用域上從根容器開始調用​

​BeginLifetimeScope()​

​方法來建立生命周期作用域。生命周期作用域是可銷毀的,他們跟蹤元件的處置,是以確定你總是調用​

​“Dispose()”​

​或者把它們包裝在​

​“using”​

​語句中。

IoC之AutoFac(三)——生命周期
1    using(var scope = container.BeginLifetimeScope())
 2   {
 3     //從作為根容器子項的作用域來解析服務
 4     var service = scope.Resolve<IService>();
 5 
 6     //您也可以建立嵌套的作用域...
 7     using(var unitOfWorkScope = scope.BeginLifetimeScope())
 8     {
 9       var anotherService = unitOfWorkScope.Resolve<IOther>();
10     }
11   }      
IoC之AutoFac(三)——生命周期

三、執行個體周期範圍

  使用這個選項,每次請求服務都會傳回一個新執行個體,這是預設選項。

var builder = new ContainerBuilder();
            builder.RegisterType<Worker>();
            builder.RegisterType<Worker>().InstancePerDependency();      

  下面的代碼,每次循環都生成一個新的執行個體,一共生成 100 個執行個體。

IoC之AutoFac(三)——生命周期
1   using(var scope = container.BeginLifetimeScope())
2   {
3     for(var i = 0; i < 100; i++)
4     {
5         //每次解析都擷取一個新執行個體
6       var w = scope.Resolve<Worker>();
7       w.DoWork();
8     }
9   }      
IoC之AutoFac(三)——生命周期

  使用這個選項,在根範圍或嵌套範圍中請求服務,都傳回同一個的執行個體。使用 SingleInstance() 指定。

var builder = new ContainerBuilder();
builder.RegisterType<Worker>().SingleInstance();      

  下面的代碼,w1 和 w2 始終是同一個對象,100 次循環隻有一個 Worker 類的執行個體。

IoC之AutoFac(三)——生命周期
using(var scope1 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    var w1 = scope1.Resolve<Worker>();
    using(var scope2 = scope1.BeginLifetimeScope())
    {
      var w2 = scope2.Resolve<Worker>();
    }
  }
}      
IoC之AutoFac(三)——生命周期

使用這個選項,在特定的 ILifetimeScope 中請求服務,隻傳回一個執行個體。下面的代碼中,scope1 中的 100 次 w1 是同一個對象,scope2 中的 100 次 w2 是同一個對象,但是 w1 和 w2 不是同一個對象。

IoC之AutoFac(三)——生命周期
1   var builder = new ContainerBuilder();
 2   builder.RegisterType<Worker>().InstancePerLifetimeScope();
 3   using(var scope1 = container.BeginLifetimeScope())
 4   {
 5     for(var i = 0; i < 100; i++)
 6     {
 7       var w1 = scope1.Resolve<Worker>();
 8     }
 9   }
10 
11   using(var scope2 = container.BeginLifetimeScope())
12   {
13     for(var i = 0; i < 100; i++)
14     {
15       var w2 = scope2.Resolve<Worker>();
16     }
17   }      
IoC之AutoFac(三)——生命周期

  類似于上面【每個生命周期範圍一個執行個體】,但可以提供更多控制。使用此選項,允許為 ILifetimeScope 對象提供“标記”。在标記比對的範圍中隻有一個執行個體。使用 InstancePerMatchingLifetimeScope() 方法指定。

var builder = new ContainerBuilder();
    builder.RegisterType<Worker>().InstancePerMatchingLifetimeScope("myscope");      

  下面的代碼中,w1 和 w2 相同,w3 和 w4 相同,但 w1 和 w3 不同。

IoC之AutoFac(三)——生命周期
1     using(var scope1 = container.BeginLifetimeScope("myscope"))
 2     {
 3       for(var i = 0; i < 100; i++)
 4       {
 5         var w1 = scope1.Resolve<Worker>();
 6         using(var scope2 = scope1.BeginLifetimeScope())
 7         {
 8           var w2 = scope2.Resolve<Worker>();
 9         }
10       }
11     }
12 
13     using(var scope3 = container.BeginLifetimeScope("myscope"))
14     {
15       for(var i = 0; i < 100; i++)
16       {
17         var w3 = scope3.Resolve<Worker>();
18         using(var scope4 = scope1.BeginLifetimeScope())
19         {
20           var w4 = scope4.Resolve<Worker>();
21         }
22       }
23     }      
IoC之AutoFac(三)——生命周期

  有些應用程式天然具有【請求】語義,例如 ASP.NET MVC 或 WebForm 應用程式。【每個請求一個執行個體】在【每個比對的生命周期範圍一個執行個體】基礎上,通過提供範圍标記,注冊函數和常見類型內建實作。本質上是【每個比對的生命周期範圍一個執行個體】。

var builder = new ContainerBuilder();
    builder.RegisterType<Worker>().InstancePerRequest();      

ASP.NET Core 使用【每個生命周期範圍一個執行個體】,而不是【每個請求一個執行個體】。

   Owned<T> 隐式關聯類型建立嵌套的生命周期範圍。使用 instance-per-owned 注冊,可将依賴限定在 owned 執行個體中。

var builder = new ContainerBuilder();
builder.RegisterType<MessageHandler>();
builder.RegisterType<ServiceForHandler>().InstancePerOwned<MessageHandler>();      

  本例中 ServiceForHandler 服務會限制在 MessageHandler 執行個體範圍内。

IoC之AutoFac(三)——生命周期
using(var scope = container.BeginLifetimeScope())
    {
      // MessageHandler 和附屬的 ServiceForHandler 
      // 在 scope 下面的一個微型的 lifetime scope 中。
      // 解析 Owned<T> 需要程式員負責執行清理工作。
      var h1 = scope.Resolve<Owned<MessageHandler>>();
      h1.Dispose();
    }      
IoC之AutoFac(三)——生命周期

InstancePerLifetimeScope,每個線程建立自己的LifetimeScope

var builder = new ContainerBuilder();
builder.RegisterType<Service>()
       .InstancePerLifetimeScope();
var container = builder.Build();      

  然後讓每個建立自己的 lifetime scope

IoC之AutoFac(三)——生命周期
void ThreadStart()
    {
      using (var threadLifetime = container.BeginLifetimeScope())
      {
        var thisThreadsInstance = threadLifetime.Resolve<MyThreadScopedComponent>();      
}      
}      
IoC之AutoFac(三)——生命周期

重要:在多線程場景下,要小心不要将父範圍清理掉。否則,派生線程中的子範圍将無法解析服務。

  每個線程都将有自己的 MyThreadScopedComponent 執行個體,本質上是生命周期範圍内的單例。範圍内的執行個體不會提供到外部,是以很容易保持線程間的元件隔離。

  通過添加 ILifetimeScope 參數,可将父範圍注入到生成線程的代碼中,Autofac 會将目前範圍自動注入,接下來可以使用它建立嵌套範圍。

IoC之AutoFac(三)——生命周期
1     public class ThreadCreator
 2     {
 3         //把父範圍注入生成線程的代碼
 4         private ILifetimeScope _parentScope;
 5         public ThreadCreator(ILifetimeScope parentScope)
 6         {
 7             this._parentScope = parentScope;
 8         }
 9 
10         public void ThreadStart()
11         {
12             using (var threadLifetime = this._parentScope.BeginLifetimeScope())
13             {
14                  //開啟一個線程時,在嵌套scope中解析,以此實作線程間元件的隔離
15                 var thisThreadsInstance = threadLifetime.Resolve<MyThreadScopedComponent>();
16             }
17         }
18      }