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


一、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”語句中。

 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   }

三、實例周期范圍

3.1   每個依賴一個實例(InstancePerDependency)

  使用這個選項,每次請求服務都會返回一個新實例,這是默認選項

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

  下面的代碼,每次循環都生成一個新的實例,一共生成 100 個實例。

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   }

3.2  單個實例(SingleInstance)

  使用這個選項,在根范圍或嵌套范圍中請求服務,都返回同一個的實例。使用 SingleInstance() 指定。

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

  下面的代碼,w1 和 w2 始終是同一個對象,100 次循環只有一個 Worker 類的實例。

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>();
    }
  }
}

3.3  每個生命周期范圍一個實例 (InstancePerLifetimeScope)

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

 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   }

3.4  每個匹配的生命周期范圍一個實例(InstancePerMatchingLifetimeScope)

  類似於上面【每個生命周期范圍一個實例】,但可以提供更多控制。使用此選項,允許為 ILifetimeScope 對象提供“標記”。在標記匹配的范圍中只有一個實例。使用 InstancePerMatchingLifetimeScope() 方法指定。

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

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

 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     }

3.5  每個請求一個實例( InstancePerRequest)

  有些應用程序天然具有【請求】語義,例如 ASP.NET MVC 或 WebForm 應用程序。【每個請求一個實例】在【每個匹配的生命周期范圍一個實例】基礎上,通過提供范圍標記,注冊函數和常見類型集成實現。本質上是【每個匹配的生命周期范圍一個實例】。

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

ASP.NET Core 使用【每個生命周期范圍一個實例】,而不是【每個請求一個實例】。

3.6  每個 Owned 一個實例 ( InstancePerOwned)

   Owned<T> 隱式關聯類型創建嵌套的生命周期范圍。使用 instance-per-owned 注冊,可將依賴限定在 owned 實例中。

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

  本例中 ServiceForHandler 服務會限制在 MessageHandler 實例范圍內。

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

3.7 線程范圍通過

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

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

  然后讓每個創建自己的 lifetime scope

   void ThreadStart()
    {
      using (var threadLifetime = container.BeginLifetimeScope())
      {
        var thisThreadsInstance = threadLifetime.Resolve<MyThreadScopedComponent>(); 
    }
  }

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

  每個線程都將有自己的 MyThreadScopedComponent 實例,本質上是生命周期范圍內的單例。范圍內的實例不會提供到外部,因此很容易保持線程間的組件隔離。

  通過添加 ILifetimeScope 參數,可將父范圍注入到生成線程的代碼中,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      }

參考文章:

1、https://blog.csdn.net/WuLex/article/details/78704903

2、http://www.yuanjiaocheng.net/Autofac/instance-scope.html

3、https://www.cnblogs.com/dongbeifeng/p/autofac-instance-scope.html


免責聲明!

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



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