Autofac筆記-LifeTimeScope(控制作用域和服務生命周期)


為什么不推薦從容器解析服務?
容器本身也是一個生命周期,你可以從容器解析服務,但是不推薦,因為容器在應用的生命周期內一直存在. 如果你直接從該容器中解析了太多東西, 應用結束時將會有一堆東西等着被釋放,很有可能造成內存泄漏
因此應該從容器創建一個子生命周期,並從中解析,當解析完后釋放子生命周期,解析的服務也一並清理了

服務的生命周期:
服務的生命周期是服務實例在程序中生存的時間。例如您“新建”一個實現IDisposable的對象,然后再對其進行調用Dispose()。

服務的范圍:
服務范圍是應用程序中可以與其他使用該服務的組件共享該服務的區域。例如,在你的應用程序中你可能有一個全局靜態的單例 - 全局對象實例的“范圍”將是整個應用程序。

Lifetime Scope(生命周期范圍):

Autofac中生命周期范圍的概念結合了這兩個概念。實際上,生命周期范圍等同於應用程序中的一個工作單元。一個工作單元可以在開始時開始一個生命周期范圍,然后該工作單元所需的服務將從一個生命周期范圍得到解析。當您解析服務時,Autofac跟蹤已解析的一次性(可配置)組件。在工作單元結束時,您將釋放相關的生命周期范圍,Autofac將自動清理/釋放解析后的服務。
務必始終從生命周期范圍而不是根容器來解析服務。由於生命周期作用域的處置跟蹤特性,如果您從容器(“根生命周期作用域”)中解析許多可丟棄組件,您可能會無意中給自己造成內存泄漏。根容器將一直保存對這些可丟棄組件的引用,直到其存在(通常是應用程序的生存期),因此它可以釋放這些組件。

手動創建作用域:

您可以通過BeginLifetimeScope()從根容器開始在任何現有生存期范圍上調用方法來創建生存期范圍。生命周期范圍是一次性的,並且它們跟蹤組件的處置,因此請確保始終調用“ Dispose()”或將它們包裝在“ using”語句中。

using(var scope = container.BeginLifetimeScope()) 
{ 
      //從容器的一個子作用域解析服務 
      var service = scope.Resolve();

      // 還可以創建嵌套的作用域
      using(var unitOfWorkScope = scope.BeginLifetimeScope()) 
      { 
            var anotherService = unitOfWorkScope.Resolve(); 
      } 
}

生命周期有以下幾種:

瞬時(Per Dependency):每次請求都會創建新實例

builder.RegisterType<Worker>().InstancePerDependency();

單例(Single Instance):所有對父容器或嵌套容器的請求都返回一個實例

builder.RegisterType<Worker>().SingleInstance();

Per Lifetime Scope:

這個作用域適用於嵌套的生命周期。一個使用Per Lifetime 作用域的component在一個 nested lifetime scope內最多有一個實例。
當對象特定於一個工作單元時,這個非常有用。比如,一個HTTP請求,每一個工作單元都會創建一個nested lifetime,如果在每一次HTTP請求中創建一個nested lifetime,那么其他使用 per-lifetime 的component在每次HTTP請求中只會擁有一個實例。

builder.RegisterType<Worker>().InstancePerLifetimeScope();

標記生命周期范圍

在某些情況下,您希望跨工作單元共享服務,但您不希望像單例模式那樣在全局共享這些服務。在這種情況下你可以使用InstancePerMatchingLifetimeScope來標識你的生命周期和服務。
舉例如下,有個發郵件的組件,事務邏輯中需要發送多次郵件,所以可以在每個邏輯事務片中共享郵件服務。然后不希望郵件組件成為全局單例,可以如下設置。

//將事務級共享組件注冊為InstancePerMatchingLifetimeScope,並給它一個“已知標記”,在啟動新事務時使用。
var builder = new ContainerBuilder();
builder.RegisterType<EmailSender>()
       .As<IEmailSender>()
       .InstancePerMatchingLifetimeScope("transaction");

// 訂單處理器和收據管理器都需要發送電子郵件通知。
builder.RegisterType<OrderProcessor>()
       .As<IOrderProcessor>();
builder.RegisterType<ReceiptManager>()
       .As<IReceiptManager>();

var container = builder.Build();
// 用標記創建作用域范圍
using(var transactionScope = container.BeginLifetimeScope("transaction"))
{
  using(var orderScope = transactionScope.BeginLifetimeScope())
  {
      //IEmailSender將“駐留”在父事務作用域中,並且在作用域中的任何子作用域中共享
    var op = orderScope.Resolve<IOrderProcessor>();
    op.ProcessOrder();
  }
  using(var receiptScope = transactionScope.BeginLifetimeScope())
  {
    var rm = receiptScope.Resolve<IReceiptManager>();
    rm.SendReceipt();
  }
}

添加注冊到生命周期范圍:

Autofac允許創建生命周期范圍時“隨時”添加注冊。當您只需要一些不希望在全局范圍內注冊的附加東西時使用此方式注冊

using(var scope = container.BeginLifetimeScope(
  builder =>
  {
    builder.RegisterType<Override>().As<IService>();
    builder.RegisterModule<MyModule>();
  }))
{
  // 額外的注冊將只在這個生命周期范圍內可用。
}

參考:
https://autofaccn.readthedocs.io/en/latest/lifetime/working-with-scopes.html
https://blog.csdn.net/WuLex/article/details/78704903


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM