1概要

このクイックチュートリアルでは、Springフレームワークのさまざまな種類のBeanスコープについて学びます。

Beanの有効範囲は、そのBeanが使用されるコンテキストにおけるそのBeanのライフサイクルと可視性を定義します。

Springフレームワークの最新版は6種類のスコープを定義しています。

シングルトン

プロトタイプ

  • リクエスト

  • セッション

  • 応用

  • websocket

前述の最後の4つのスコープ

request、session、application

および


websocket __はWeb対応アプリケーションでのみ利用可能です。


2シングルトンスコープ


singleton

スコープを使用してBeanを定義すると、コンテナはそのBeanの単一インスタンスを作成し、そのBean名に対するすべての要求は同じオブジェクトを返します。これはキャッシュされます。オブジェクトへの変更はすべて、Beanへのすべての参照に反映されます。他の範囲が指定されていない場合、この範囲がデフォルト値です。

スコープの概念を例示するために

Person

エンティティを作成しましょう。

public class Person {
    private String name;

   //standard constructor, getters and setters
}

その後、

@ Scope

アノテーションを使用して

singleton

スコープを持つBeanを定義します。

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

次のようにして、

String

値の代わりに定数を使用することもできます。

@Scope(value = ConfigurableBeanFactory.SCOPE__SINGLETON)

今度は、同じBeanを参照している2つのオブジェクトが同じBeanインスタンスを参照しているため、どちらか一方だけが状態を変更しても、同じ値を持つことを示すテストを作成します。

private static final String NAME = "John Smith";

@Test
public void givenSingletonScope__whenSetName__thenEqualNames() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scopes.xml");

    Person personSingletonA = (Person) applicationContext.getBean("personSingleton");
    Person personSingletonB = (Person) applicationContext.getBean("personSingleton");

    personSingletonA.setName(NAME);
    Assert.assertEquals(NAME, personSingletonB.getName());

    ((AbstractApplicationContext) applicationContext).close();
}

この例の

scopes.xml

ファイルには、使用されるBeanのXML定義が含まれています。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="personSingleton" class="org.baeldung.scopes.Person" scope="singleton"/>
</beans>


3プロトタイプスコープ


prototype

スコープを持つBeanは、コンテナから要求されるたびに異なるインスタンスを返します。 Bean定義で

prototype



@ Scope

アノテーションに設定することで定義されます。

@Bean
@Scope("prototype")
public Person personPrototype() {
    return new Person();
}

シングルトンスコープに対して行ったように、定数を使用することもできます。

@Scope(value = ConfigurableBeanFactory.SCOPE__PROTOTYPE)

スコーププロトタイプで同じBean名を要求する2つのオブジェクトは、同じBeanインスタンスを参照していないため、状態が異なることを示す前と同様のテストを作成します。

private static final String NAME = "John Smith";
private static final String NAME__OTHER = "Anna Jones";

@Test
public void givenPrototypeScope__whenSetNames__thenDifferentNames() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scopes.xml");

    Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");
    Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");

    personPrototypeA.setName(NAME);
    personPrototypeB.setName(NAME__OTHER);

    Assert.assertEquals(NAME, personPrototypeA.getName());
    Assert.assertEquals(NAME__OTHER, personPrototypeB.getName());

    ((AbstractApplicationContext) applicationContext).close();
}


scopes.xml

ファイルは、前のセクションで示したものと似ていますが、

prototype

スコープを持つBeanのxml定義が追加されています。

<bean id="personPrototype" class="org.baeldung.scopes.Person" scope="prototype"/>


4 Web対応の範囲

前述のように、Web対応アプリケーションのコンテキストでのみ利用可能な4つの追加のスコープがあります。これらは実際にはあまり使われません。


request

スコープは単一のHTTPリクエスト用のBeanインスタンスを作成し、s

__ession

__スコープはHTTPセッション用に作成します。


__application


scopeはライフサイクル

ServletContext

のBeanインスタンスを作成し、


webbsocket


scopeは特定の


WebSocket

__sessionに対して作成します。

Beanのインスタンス化に使用するクラスを作成しましょう。

public class HelloMessageGenerator {
    private String message;

   //standard getter and setter
}


4.1. リクエスト範囲


@ Scope

アノテーションを使用して

request

スコープでBeanを定義できます。

@Bean
@Scope(value = WebApplicationContext.SCOPE__REQUEST, proxyMode = ScopedProxyMode.TARGET__CLASS)
public HelloMessageGenerator requestScopedBean() {
    return new HelloMessageGenerator();
}

Webアプリケーションコンテキストのインスタンス化の時点ではアクティブな要求がないため、

proxyMode

属性が必要です。 Springは依存関係として注入されるプロキシを作成し、リクエストで必要になったときにターゲットBeanをインスタンス化します。

次に、

requestScopedBean

への注入された参照を持つコントローラを定義できます。 Web固有のスコープをテストするために、同じリクエストに2回アクセスする必要があります。

リクエストが実行されるたびに

message

を表示すると、後でメソッド内で変更されていても、値が

null

にリセットされていることがわかります。これは、リクエストごとに異なるBeanインスタンスが返されるためです。

@Controller
public class ScopesController {
    @Resource(name = "requestScopedBean")
    HelloMessageGenerator requestScopedBean;

    @RequestMapping("/scopes/request")
    public String getRequestScopeMessage(final Model model) {
        model.addAttribute("previousMessage", requestScopedBean.getMessage());
        requestScopedBean.setMessage("Good morning!");
        model.addAttribute("currentMessage", requestScopedBean.getMessage());
        return "scopesExample";
    }
}


4.2. セッションスコープ

同様の方法で

session

スコープでbeanを定義できます

@Bean
@Scope(value = WebApplicationContext.SCOPE__SESSION, proxyMode = ScopedProxyMode.TARGET__CLASS)
public HelloMessageGenerator sessionScopedBean() {
    return new HelloMessageGenerator();
}

次に、

sessionScopedBean

を参照してコントローラーを定義します。繰り返しますが、

message

フィールドの値がセッションで同じであることを示すために、2つのリクエストを実行する必要があります。

この場合、初めて要求が出されたときには、値

message

は____nullです。ただし、一度変更すると、セッション全体で同じBeanのインスタンスが返されるため、後続の要求に対してその値が保持されます。

@Controller
public class ScopesController {
    @Resource(name = "sessionScopedBean")
    HelloMessageGenerator sessionScopedBean;

    @RequestMapping("/scopes/session")
    public String getSessionScopeMessage(final Model model) {
        model.addAttribute("previousMessage", sessionScopedBean.getMessage());
        sessionScopedBean.setMessage("Good afternoon!");
        model.addAttribute("currentMessage", sessionScopedBean.getMessage());
        return "scopesExample";
    }
}


4.3. 適用範囲


__application


scopeは、

ServletContextのライフサイクルのBeanインスタンスを作成します

これはシングルトンスコープに似ていますが、Beanのスコープに関して非常に重要な違いがあります。

Beanが

application

スコープの場合、Beanの同じインスタンスは同じ

ServletContext

内で実行されている複数のサーブレットベースのアプリケーション間で共有されますが、singletonスコープのBeanは単一のアプリケーションコンテキストのみにスコープされます。


application

スコープでBeanを作成しましょう。

@Bean
@Scope(value = WebApplicationContext.SCOPE__APPLICATION, proxyMode = ScopedProxyMode.TARGET__CLASS)
public HelloMessageGenerator applicationScopedBean() {
    return new HelloMessageGenerator();
}

そして、このBeanを参照するコントローラは、

@Controller
public class ScopesController {
    @Resource(name = "applicationScopedBean")
    HelloMessageGenerator applicationScopedBean;

    @RequestMapping("/scopes/application")
    public String getApplicationScopeMessage(final Model model) {
        model.addAttribute("previousMessage", applicationScopedBean.getMessage());
        applicationScopedBean.setMessage("Good afternoon!");
        model.addAttribute("currentMessage", applicationScopedBean.getMessage());
        return "scopesExample";
    }
}

この場合、

__applicationScopedBeanに設定された値

message

は、後続のすべてのリクエスト、セッション、および同じ

ServletContextで実行されている場合はこのBeanにアクセスする別のサーブレットアプリケーションでも保持されます。


4.4. WebSocketスコープ

最後に、


_ webbsocket

_

scopeでBeanを作成しましょう。

@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET__CLASS)
public HelloMessageGenerator websocketScopedBean() {
    return new HelloMessageGenerator();
}

最初にアクセスしたときのWebSocketスコープのBeanは、

WebSocket

セッション属性に格納されています。 WebSocketセッション全体でそのBeanがアクセスされるたびに、そのBeanの同じインスタンスが返されます。

また、これはシングルトンの動作を示しますが、

WebSocket

セッションのみに制限されていると言えます。


5結論

Springによって提供されるさまざまなBeanスコープとそれらの意図された使用法が何であるかを実証しました。

このチュートリアルの実装はhttps://github.com/eugenp/tutorials/tree/master/spring-all[githubプロジェクト]にあります – これはEclipseベースのプロジェクトなので、インポートと実行は簡単なはずです。そのまま。