天天看點

Autofac容器對象執行個體的幾種生命周期類型

執行個體範圍決定了如何在同一服務的請求之間共享執行個體。 請注意,您應該熟悉生命周期範圍的概念,以便更好地了解此處發生的情況。

當請求服務時,Autofac可以傳回單個執行個體(單執行個體作用域),新執行個體(每個依賴作用域)或某種上下文中的單個執行個體,例如 線程或HTTP請求(每個生命周期範圍)。

這适用于從顯式

Resolve()

調用傳回的執行個體以及容器内部建立的執行個體,以滿足另一個元件的依賴關系。

選擇正确的生命周期範圍将有助于避免元件壽命過長或不夠長的俘獲依賴和其他陷阱。 開發人員需要為每個應用程式元件做出正确的選擇。

1.Instance Per Dependency

每次都會傳回一個新的執行個體,并且這是預設的生命周期。

var builder = new ContainerBuilder();

// This...
builder.RegisterType<Worker>();

// 此句代碼的效果同上
builder.RegisterType<Worker>().InstancePerDependency();
           

當您解析每個依賴項的執行個體元件時,每次都會得到一個新元件。

using(var scope = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    // Every one of the 100 Worker instances
    // resolved in this loop will be brand new.
    var w = scope.Resolve<Worker>();
    w.DoWork();
  }
}
           

2.Single Instance

單例,所有服務請求都将會傳回同一個執行個體。

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

當您解析單個執行個體元件時,無論您請求何處,都始終獲得相同的執行個體。

// It's generally not good to resolve things from the
// container directly, but for singleton demo purposes
// we do...
var root = container.Resolve<Worker>();

// We can resolve the worker from any level of nested
// lifetime scope, any number of times.
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>();

      // root, w1, and w2 are always literally the
      // same object instance. It doesn't matter
      // which lifetime scope it's resolved from
      // or how many times.
    }
  }
}
           

3.Instance Per Lifetime Scope

在一個嵌套語句塊中,隻會傳回一個執行個體。

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

在解決每個生命周期執行個體作用域元件時,每個嵌套作用域将獲得一個執行個體(例如,每個工作單元)。

using(var scope1 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    // 每次從這裡解析它
    // 你會得到相同的執行個體。
    var w1 = scope1.Resolve<Worker>();
  }
}

using(var scope2 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    //每次從這裡解析它
    //每次解析都會得到一個同樣的執行個體,但是這個示例和上面的循環的執行個體不是同一個
    var w2 = scope2.Resolve<Worker>();
  }
}
           

4.Instance Per Matching Lifetime Scope

這與上面的'每個生命周期的執行個體範圍'概念類似,但允許更精确地控制執行個體共享。

當您建立嵌套的生存期範圍時,您可以“标記”或“命名”範圍。具有每比對生命周期範圍的元件每個嵌套生命周期範圍最多隻有一個執行個體與給定名稱比對。這允許您建立一種“範圍單例”,其中嵌套的生命周期範圍可以在不聲明全局共享執行個體的情況下共享某個元件的執行個體。

這對于特定于單個工作單元的對象是有用的,例如,一個HTTP請求,作為一個嵌套的生命周期可以建立每個工作單元。如果每個HTTP請求都建立一個嵌套的生命周期,那麼每個具有每個生命周期範圍的元件都将為每個HTTP請求建立一個執行個體。 (有關每個請求生命周期範圍的更多資訊。)

在大多數應用中,隻有一層容器嵌套足以代表工作單元的範圍。如果需要更多級别的嵌套(例如像global-> request-> transaction這樣的東西),元件可以配置為使用标簽在層次結構中的特定級别共享。

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

提供的标記值在啟動時與生存期範圍關聯。 如果在沒有正确命名的生命周期範圍時嘗試解析每個比對生命周期範圍的元件,則會得到一個異常。

//使用标簽建立生命周期
using(var scope1 = container.BeginLifetimeScope("myrequest"))
{
  for(var i = 0; i < 100; i++)
  {
    var w1 = scope1.Resolve<Worker>();
    using(var scope2 = scope1.BeginLifetimeScope())
    {
      var w2 = scope2.Resolve<Worker>();

       // w1和w2始終是同一個對象
       //執行個體,因為該元件是每個比對生命周期範圍的,
       //是以它實際上是一個單例
       //命名範圍
    }
  }
}

//使用标簽建立另一個生命周期作用域
using(var scope3 = container.BeginLifetimeScope("myrequest"))
{
  for(var i = 0; i < 100; i++)
  {
    // w3 will be DIFFERENT than the worker resolved in the
    // earlier tagged lifetime scope.
    var w3 = scope3.Resolve<Worker>();
    using(var scope4 = scope3.BeginLifetimeScope())
    {
      var w4 = scope4.Resolve<Worker>();

       // w3和w4始終是同一個對象,因為
       //他們在相同的标記範圍内,但他們是
       //與之前的w1,w2不一樣。
    }
  }
}
//你無法解析每個比對生命周期的元件
//如果沒有比對的範圍。
using(var noTagScope = container.BeginLifetimeScope())
{
   //因為這個範圍沒有,是以抛出一個異常
   //有預期的标簽,也沒有任何父範圍!
  var fail = noTagScope.Resolve<Worker>();
}
           

5.Instance Per Request

某些應用程式類型自然适用于“請求”類型語義,例如ASP.NET Web Forms和MVC應用程式。 在這些應用程式類型中,有能力為每個請求提供一種“單例”。

通過提供衆所周知的生命周期範圍标記,注冊便利方法以及針對常見應用程式類型的內建,每個請求的執行個體基于每個比對生命周期範圍的執行個體建構。 但在幕後,它仍然隻是每個比對生命周期範圍的執行個體。

這意味着如果您嘗試解析注冊為每個請求執行個體但沒有目前請求的元件,那麼您将得到一個異常。

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

6.Instance Per Owned

擁有的隐式關系類型建立新的嵌套生命周期作用域。 可以使用每個擁有執行個體的注冊來将依賴關系限定到擁有的執行個體。

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

在這個例子中,

ServiceForHandler

服務将被限制在擁有的

MessageHandler

執行個體的生命周期中。

using(var scope = container.BeginLifetimeScope())
{
   //消息處理程式本身以及
   //解析依賴的ServiceForHandler服務
   //在一個小小的生命周期範圍内
   // “範圍。” 請注意解析一個擁有的<T>
   //表示您負責處理。
  var h1 = scope.Resolve<Owned<MessageHandler>>();
  h1.Dispose();
}
           

原文:http://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html

目前學習.NET Core 最好的教程 .NET Core 官方教程 ASP.NET Core 官方教程

.NET Core 交流群:923036995  歡迎加群交流

如果您認為這篇文章還不錯或者有所收獲,您可以點選右下角的【推薦】支援,或請我喝杯咖啡【贊賞】,這将是我繼續寫作,分享的最大動力!

作者:曉晨Master(李志強)

聲明:原創部落格請在轉載時保留原文連結或者在文章開頭加上本人部落格位址,如發現錯誤,歡迎批評指正。凡是轉載于本人的文章,不能設定打賞功能,如有特殊需求請與本人聯系!

繼續閱讀