Scope
Posted by Bruce Tsai
在 Spring 所管控的 bean 中,每個 bean 有其生命週期存在。其中最基本類型的為 Singleton 與 Prototype 兩類。
基本的 Scope
- Singleton : ConfigurableBeanFactory.SCOPE_PROTOTYPE,意指物件本身為單一實體的設計,所有對同一類別的 bean 的存取,都會指向同一個 instance。也就是說,單一實體的物件在程式初始化後就不會再有其它的實體產生,主要會使用在服務類型的 bean。
- Prototype : ConfigurableBeanFactory.SCOPE_SINGLETON,原始模式,意即與使用
new
關鍵字進行初始化相同,每一個實體的物件各自獨立,擁有自己的記憶體存放區,主要使用在有自我的存取屬性的 bean。
未指定 Scope (預設為 Singleton)
@Component
public class SingleComponent {
}
SingleComponent s1 = context.getBean(SingleComponent.class);
SingleComponent s2 = context.getBean(SingleComponent.class);
System.out.printf("SingleComponent s1: %s%n", s1);
System.out.printf("SingleComponent s2: %s%n", s2);
System.out.printf("s1 == s2: %b%n", s1 == s2);
SingleComponent s1: com.foo.core.SingleComponent@61dd025
SingleComponent s2: com.foo.core.SingleComponent@61dd025
s1 == s2: true
Scope 為 Singleton
@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class SingleComponent2 {
}
SingleComponent2 s1 = context.getBean(SingleComponent2.class);
SingleComponent2 s2 = context.getBean(SingleComponent2.class);
System.out.printf("SingleComponent2 s1: %s%n", s1);
System.out.printf("SingleComponent2 s2: %s%n", s2);
System.out.printf("s1 == s2: %b%n", s1 == s2);
SingleComponent2 s1: com.foo.core.SingleComponent2@61dd025
SingleComponent2 s2: com.foo.core.SingleComponent2@61dd025
s1 == s2: true
Scope 為 Prototype
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PrototypeComponent {
}
PrototypeComponent p1 = context.getBean(PrototypeComponent.class);
PrototypeComponent p2 = context.getBean(PrototypeComponent.class);
System.out.printf("SingleComponent2 p1: %s%n", p1);
System.out.printf("SingleComponent2 p2: %s%n", p2);
System.out.printf("p1 == p2: %b%n", p1 == p2);
SingleComponent2 p1: com.foo.core.PrototypeComponent@61dd025
SingleComponent2 p2: com.foo.core.PrototypeComponent@124c278f
p1 == p2: false
Web 應用程式的 Scope
Request、session 和 Global-session 三種 scope 只能在 web 環境中使用,如果在非 web 環境設定,會出現 No Scope registered for scope 'request'
的錯誤。
- Request : 在每一次的 HTTP Request,Spring 會根據 bean 的定義來建立一個全新的instance,而且僅在目前的 request 中有效,所以可以放心的去更改 instance 的內部狀態。當請求結束時,request scope 的 bean instance 會被釋放。
- Session : 針對某個 HTTP Session,Spring 會根據 bean 的定義來建立一個全新的instance,同樣的,和 request scope 一樣,可以放心的去更改 instance 內部狀態。
- Global Session : 僅在以 portlet 為基礎的 web 應用下有作用。Porlet 的規範中定義了global session 的概念。
@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestComponent {
}
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionComponent {
}
@Component
@Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class GlobalSessionComponent {
}
- 補充:因 request、session、global-session 的生命週期是依據執行時才產生,無法在應用程式初始化時建立實體,因此需要設定 proxyMode,來建立 AOP proxy,以注入週期較短的 bean。