Guice系列之用户指南(十)
原文地址:https://code.google.com/p/google-guice/wiki/Scopes
Scopes:作用域。
默認情況下,Guice每次在調用時都會返回一個新的實例,這種行為是可以通過作用域配置的,作用域允許復用對象實例。在一個應用服務的生命周期中,對象可能是單例的(@Singleton),也可能是一個回話的(@SessionScoped),也可能是一個請求的(@RequestScoped)。Guice在web應用中也包含一個servlet擴展的作用域。自定義作用域可以在不同類型的應用中使用。
Applying Scopes
作用域使用有不用的方式,例如注解,
| 1 2 3 4 | @Singleton public class InMemoryTransactionLog implements TransactionLog { ??/* everything here should be threadsafe! */ } |
也可以配置在代碼里,
| 1 | bind(TransactionLog.class).to(InMemoryTransactionLog.class).in(Singleton.class); |
也可以注解在@Provides方法處,
| 1 2 3 4 | @Provides @Singleton ??TransactionLog provideTransactionLog() { ????... ??} |
如果有些沖突的作用域同時在一個類型上或者代碼里的bind()方法上配置,那么bind()的配置生效。如果一個類型你不想給它設置要作用域,那么就綁定Scopes.NO_SCOPE。
像鏈接綁定那樣,作用域應用于綁定的父類型,而不是綁定目標實現類。設想我們有一個同時實現Bar接口和Grill接口的實現類Applebees,這就要求需要同時綁定的這兩種類型,一種是類型Bar,另一種是Grill:
| 1 2 | bind(Bar.class).to(Applebees.class).in(Singleton.class); bind(Grill.class).to(Applebees.class).in(Singleton.class); |
這是因為作用域應用于這個綁定的類型(Bar,Grill),而不是滿足這個類型的實現類Applebees,為了允許只有一個實例,用一個注解@Singleton聲明在父類型上,或者在代碼里綁定。
| 1 | bind(Applebees.class).in(Singleton.class); |
這種綁定使得以上的其他兩種.in(Singleton.class)語句不必要。這種in()語句還接受像RequestScoped.class或者是ServletScopes.REQUEST的注解:
| 1 2 3 | bind(UserPreferences.class) ??????.toProvider(UserPreferencesProvider.class) ??????.in(ServletScopes.REQUEST); |
這種注解是推薦優先的,因為它允許這個模塊在不同的類型應用中復用,打個比方,一個被@RequestScoped注解的對象即能夠在web應用的http請求中被使用,也可以在一個API服務器的rpc中被使用。
Eager Singletons
Eager Singletons(各種饑渴的單例):不是延遲的,是餓漢式的單例。
Guice有特殊的語法定義把單例為餓漢式的:
| 1 | bind(TransactionLog.class).to(InMemoryTransactionLog.class).asEagerSingleton(); |
Guice有特殊的語法定義把單例為饑渴的:
餓漢式的單例可以很快揭示初始化問題,并確保最終用戶獲得一致的,直觀的體驗。懶漢式的單例保證了一個快速的編輯-完成-啟動的開發周期,用這個Stage的枚舉可以區分那種策略被使用:
| PRODUCTION | DEVELOPMENT | |
| .asEagerSingleton() | eager | eager |
| .in(Singleton.class) | eager | lazy |
| .in(Scopes.SINGLETON) | eager | lazy |
| @Singleton | eager* | lazy |
Guice會在已知類型的情況下創建餓漢式單例,這些類型都是在自己的模塊,并加上這些類型遞歸依賴提到的類型。
Choosing a scope
選擇一種作用域,如果一個對象是有狀態的,那么這個作用域就明顯了,每個應用都是@Singleton的,每個請求都是@RequestScoped等等。如果一個對象是沒有狀態的,并且創建開銷是很小的,那么作用域就沒有必要,就不用綁定作用域,Guice會按需要創建不同的實例。
許多單例在java應用中是很流行的但是但它們沒有提供多大的價值,尤其是當涉及依賴注入。盡管單例可以節省對象創建開銷,或者晚一點的垃圾回收,獲取一個單例的句柄得到需要同步。單例是很有用的:
有狀態的對象,例如配置或者計數
創建昂貴或者查找昂貴的對象
占用資源,如數據庫連接池對象
Scopes and Concurrency
作用域和并發,類型被@Singleton和@SessionScoped注解的一定是線程安全的,任何被注入到這些類型的也一定是線程安全的,減少可變性來限制一些需要并發保護的狀態。
@RequestScoped對象不需要線程安全,一個@Singleton和@SessionScoped對象來依賴@RequestScoped對象,這是一個錯誤常識。如果你需要一個對象在一個較窄的范圍內,注入該對象的提供者。
總結
以上是生活随笔為你收集整理的Guice系列之用户指南(十)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何从代码层面优化系统性能
- 下一篇: STM8不用手动复位进入自带Bootlo