spring
ビーンスコープ
サーチ…
シングルトンスコープ
Beanがシングルトンスコープで定義されている場合、Springコンテナで初期化された単一のオブジェクトインスタンスのみが存在します。このBeanに対するすべての要求は、同じ共有インスタンスを返します。これは、Beanを定義するときのデフォルトのスコープです。
次のMyBeanクラスがあるとします。
public class MyBean {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
private String property;
public MyBean(String property) {
this.property = property;
LOGGER.info("Initializing {} bean...", property);
}
public String getProperty() {
return this.property;
}
public void setProperty(String property) {
this.property = property;
}
}
@Beanアノテーションを使ってシングルトンBeanを定義することができます:
@Configuration
public class SingletonConfiguration {
@Bean
public MyBean singletonBean() {
return new MyBean("singleton");
}
}
次の例では、Springコンテキストから同じBeanを2回取得します。
MyBean singletonBean1 = context.getBean("singletonBean", MyBean.class);
singletonBean1.setProperty("changed property");
MyBean singletonBean2 = context.getBean("singletonBean", MyBean.class);
singletonBean2プロパティを記録すると、同じ共有インスタンスを取得したので、メッセージ"changed properties"が表示されます。
インスタンスは異なるコンポーネント間で共有されるため、ステートレスオブジェクトのシングルトンスコープを定義することをお勧めします。
レイジーシングルトンビーンズ
既定では、シングルトンBeanは事前インスタンス化されています。したがって、共有オブジェクトインスタンスは、Springコンテナが作成されるときに作成されます。アプリケーションを起動すると、 "Initializing singleton bean ..."というメッセージが表示されます。
Beanを事前にインスタンス化したくない場合は、Bean定義に@Lazyアノテーションを追加できます。これにより、Beanが最初に要求されるまでBeanが作成されなくなります。
@Bean
@Lazy
public MyBean lazySingletonBean() {
return new MyBean("lazy singleton");
}
さて、Springコンテナを起動すると、 "Initialize lazy singleton bean ..."というメッセージは表示されません。 Beanは、初めて要求されるまで作成されません。
logger.info("Retrieving lazy singleton bean...");
context.getBean("lazySingletonBean");
シングルトンビーンとレイジーシングルトンビーンの両方を定義してアプリケーションを実行すると、次のメッセージが生成されます。
Initializing singleton bean...
Retrieving lazy singleton bean...
Initializing lazy singleton bean...
プロトタイプスコープ
プロトタイプスコープのBeanは、Springコンテナの起動時に事前に作成されません。代わりに、このBeanの取得要求がコンテナに送信されるたびに、新しい新しいインスタンスが作成されます。このスコープは、状態が他のコンポーネントと共有されないため、ステートフルオブジェクトには推奨されます。
プロトタイプスコープのBeanを定義するには、スコープの種類を指定して@Scopeアノテーションを追加する必要があります。
次のMyBeanクラスがあるとします。
public class MyBean {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBean.class);
private String property;
public MyBean(String property) {
this.property = property;
LOGGER.info("Initializing {} bean...", property);
}
public String getProperty() {
return this.property;
}
public void setProperty(String property) {
this.property = property;
}
}
Bean定義を定義し、そのスコープをプロトタイプとして示します。
@Configuration
public class PrototypeConfiguration {
@Bean
@Scope("prototype")
public MyBean prototypeBean() {
return new MyBean("prototype");
}
}
どのように動作するかを見るために、SpringコンテナからBeanを取得し、そのプロパティフィールドに異なる値を設定します。次に、コンテナからBeanを再度取得し、その値を参照します。
MyBean prototypeBean1 = context.getBean("prototypeBean", MyBean.class);
prototypeBean1.setProperty("changed property");
MyBean prototypeBean2 = context.getBean("prototypeBean", MyBean.class);
logger.info("Prototype bean 1 property: " + prototypeBean1.getProperty());
logger.info("Prototype bean 2 property: " + prototypeBean2.getProperty());
次の結果を見ると、各Beanリクエストで新しいインスタンスがどのように作成されたかを確認できます。
Initializing prototype bean...
Initializing prototype bean...
Prototype bean 1 property: changed property
Prototype bean 2 property: prototype
一般的な間違いは、呼び出しごとまたはスレッドごとにBeanが再作成されると仮定することです。これは当てはまりません 。インスタンスは、PER INJECTION(またはコンテキストからの取得)の代わりに作成されます。プロトタイプスコープBeanが1つのシングルトンBeanにのみ注入されると、そのPrototypeスコープBeanのインスタンスは1つしか存在しません。
Springは、プロトタイプBeanの完全なライフサイクルを管理しません。コンテナは、プロトタイプオブジェクトをインスタンス化、コンフィグレーション、デコレート、その他の方法でアセンブルしてクライアントに渡し、そのプロトタイプインスタンスの詳細を知りません。
Web対応コンテキストの追加スコープ
Web対応アプリケーションのコンテキストでのみ使用可能なスコープがいくつかあります。
- request - HTTPリクエストごとに新しいBeanインスタンスが作成されます。
- session - HTTPセッションごとに新しいBeanインスタンスが作成されます。
- アプリケーション -
ServletContext
ごとに新しいBeanインスタンスが作成される - globalSession - ポートレット環境でグローバルセッションごとに新しいBeanインスタンスが作成されます(サーブレット環境ではグローバルセッションスコープはセッションスコープに等しい)
- websocket - WebSocketセッションごとに新しいBeanインスタンスが作成されます。
Spring Web MVC環境でWebスコープBeanを宣言してアクセスするための追加設定は不要です。
XML設定
<bean id="myRequestBean" class="OneClass" scope="request"/>
<bean id="mySessionBean" class="AnotherClass" scope="session"/>
<bean id="myApplicationBean" class="YetAnotherClass" scope="application"/>
<bean id="myGlobalSessionBean" class="OneMoreClass" scope="globalSession"/>
Java設定(Spring 4.3より前)
@Configuration
public class MyConfiguration {
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public OneClass myRequestBean() {
return new OneClass();
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public AnotherClass mySessionBean() {
return new AnotherClass();
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public YetAnotherClass myApplicationBean() {
return new YetAnotherClass();
}
@Bean
@Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public OneMoreClass myGlobalSessionBean() {
return new OneMoreClass();
}
}
Java設定(Spring 4.3以降)
@Configuration
public class MyConfiguration {
@Bean
@RequestScope
public OneClass myRequestBean() {
return new OneClass();
}
@Bean
@SessionScope
public AnotherClass mySessionBean() {
return new AnotherClass();
}
@Bean
@ApplicationScope
public YetAnotherClass myApplicationBean() {
return new YetAnotherClass();
}
}
注釈駆動コンポーネント
@Component
@RequestScope
public class OneClass {
...
}
@Component
@SessionScope
public class AnotherClass {
...
}
@Component
@ApplicationScope
public class YetAnotherClass {
...
}
@Component
@Scope(scopeName = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class OneMoreClass {
...
}
@Component
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AndOneMoreClass {
...
}