服務的生命週期:是服務實例在您的應用程序中生存的時間 ,即從原始實例化到釋放期間。例如,若是你「新建」了一個實現了IDisposable
的對象,而後再調用Dispose()
,那麼這個對象的生命週期就是從你實例化的時候開始,被釋放時結束(或者垃圾回收,若是你沒有主動處置它)。html
服務範圍:應用程序中能夠與其餘使用該服務的組件共享該服務的區域。例如,在你的應用程序中你可能有一個全局靜態的單例 - 全局對象實例的「範圍」將是整個應用程序。另外一方面,您能夠在使用全局單例的for循環中建立局部變量 - 局部變量的範圍比全局範圍小得多。程序員
Autofac
中的生命週期概念:結合了這兩個概念。生命週期的範圍等同於您的應用程序中的一個工做單元。在解析服務問題時,Autofac
跟蹤已解析的一次性(IDisposable
)組件,在工做單元結束時,您將釋放關聯的生命週期範圍(scope),Autofac
將自動清理/處理已解析的服務。多線程
生命週期管理的兩件重要的事情就是共享和清理。併發
咱們來看一個Web應用程序做爲更具體的例子來講明生命週期範圍的使用。 假設你有如下狀況:函數
你有一個全局的單例日誌記錄服務。 兩個併發請求進入Web應用程序。 每一個請求都是一個邏輯的「工做單元」,每一個請求都須要本身的訂單處理服務。 每一個訂單處理服務都須要將日信息記錄到日誌服務中。
在這種狀況下,您將擁有包含單例記錄服務的根生存期範圍,而且每一個請求都有一個子生命週期範圍,每一個範圍都有本身的訂單處理服務:ui
+---------------------------------------------------+ | 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)被處理,相應的訂單處理服務被銷燬。 日誌記錄服務做爲一個單例對象,在未來的請求中保持共享。this
您能夠經過在任何現有生命週期做用域上從根容器開始調用BeginLifetimeScope()
方法來建立生命週期做用域。生命週期做用域是可銷燬的,他們跟蹤組件的處置,因此確保你老是調用「Dispose()」
或者把它們包裝在「using」
語句中。spa
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 }
使用這個選項,每次請求服務都會返回一個新實例,這是默認選項。.net
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 }
使用這個選項,在根範圍或嵌套範圍中請求服務,都返回同一個的實例。使用 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>(); } } }
使用這個選項,在特定的 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 }
相似於上面【每一個生命週期範圍一個實例】,但能夠提供更多控制。使用此選項,容許爲 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 }
有些應用程序自然具備【請求】語義,例如 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 實例範圍內。
using(var scope = container.BeginLifetimeScope()) { // MessageHandler 和附屬的 ServiceForHandler // 在 scope 下面的一個微型的 lifetime scope 中。 // 解析 Owned<T> 須要程序員負責執行清理工做。 var h1 = scope.Resolve<Owned<MessageHandler>>(); h1.Dispose(); }
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 }
參考文章:
一、https://blog.csdn.net/WuLex/article/details/78704903
二、http://www.yuanjiaocheng.net/Autofac/instance-scope.html
三、https://www.cnblogs.com/dongbeifeng/p/autofac-instance-scope.html