Springコンテナーでのシングルトン設計パターンとシングルトンBean


90

SpringコンテナにはデフォルトでシングルトンとしてBeanがあり、Springフレームワークに基づくWebアプリケーションがある場合、Springを通じてBeanを作成するだけでなく、グローバルデータを保持するシングルトンデザインパターンを実装する必要があります。 。

私が実際に尋ねようとしていたことを説明できない場合は、ご容赦ください。

回答:


60

SpringのシングルトンBeanとシングルトンパターンはまったく異なります。シングルトンパターンは、特定のクラスのインスタンスがクラスローダーごとに1つだけ作成されることを示しています。

Springシングルトンのスコープは、「Beanごとのコンテナーごと」として記述されます。これは、Spring IoCコンテナーごとの単一オブジェクトインスタンスへのBean定義のスコープです。Springのデフォルトのスコープはシングルトンです。

デフォルトのスコープはシングルトンですが、<bean ../>要素のスコープ属性を指定することで、Beanのスコープを変更できます。

<bean id=".." class=".." scope="prototype" />

12
@ user184794:コンテナーごと、Beanごと、つまり、Spring Containerにクラスローダーが1つしかない場合。SpringContainerに2つ以上のクラスローダーがある場合、各クラスローダーは独自のインスタンスを持ちます。「コンテナごと、クラスローダーごと、Beanごと」という意味ですか。親切に明確にしてください!!
デッドプログラマ

4
私はそれがSpringコンテナが所有する単一のクラスローダーを使用することを意味すると思います。あなたが春のメカニズム外でやっていることはつまり、あなたがあなた自身のクラスローダーを作成し、あなたが望むように、クラスの多くのインスタンスとして作成していますが、Springコンテナを通過した場合、それは複数のインスタンスを作成しませんすることができ、関係ありません
inor

1
そうすれば、あなたが言うように、それらは「まったく異なる」ものではありません。唯一の違いはスコープです-Springコンテナとクラスローダーの比較
Zack Macomber

30

Springのシングルトンスコープは、Springコンテキストの単一のインスタンスを意味します
。Springコンテナは、Beanを取得するための後続の呼び出しで同じインスタンスを何度も返すだけです。


そして、Beanのクラスがシングルトンとしてコーディングされているかどうかにかかわらず、Springは気にしません。実際、クラスがプライベートとしてコンストラクターを持つシングルトンとしてコーディングされている場合、SpringはBeanUtils.instantiateClass(ここでは javadoc )を使用してコンストラクターをアクセス可能に設定し、呼び出しますそれ。

あるいは、次のようなBean定義でfactory-method属性を使用できます。

    <bean id="exampleBean" class="example.Singleton"  factory-method="getInstance"/>

1
あなたはfactory-method属性が必要ですか?私は春が(おそらくのgetInstanceを呼び出ししようとします)コンストラクタがプライベートであっても、インスタンスを取得する方法を知っている確信している
inor

春はプライベートコンストラクタを呼び出す方法については、関連する議論こちら
Xiawei張

21

最も単純な例を見てみましょう。アプリケーションがあり、デフォルトのクラスローダーを使用するだけです。何らかの理由で、アプリケーションに複数のインスタンスを含めないようにするクラスがあるとします。(数人がアプリケーションの一部で作業するシナリオを考えてください)。

Springフレームワークを使用していない場合、シングルトンパターンは、アプリケーション内にクラスのインスタンスが複数存在しないことを保証します。これは、コンストラクタがプライベートであるため、「新規」を実行してクラスのインスタンスをインスタンス化できないためです。クラスのインスタンスを取得する唯一の方法は、常に同じインスタンスを返すクラスの静的メソッド(通常は「getInstance」と呼ばれる)を呼び出すことです。

アプリケーションでSpringフレームワークを使用していると言うと、クラスのインスタンスを取得する通常の方法(クラスのインスタンスを返す新しいメソッドまたは静的メソッド)に加えて、Springに要求することもできますそのクラスとSpringのインスタンスは、シングルトンパターンを使用してクラスを作成しなかった場合でも、そのクラスのインスタンスを要求するときは常に同じインスタンスを返すことを保証します。つまり、クラスにパブリックコンストラクターがある場合でも、常にそのクラスのインスタンスをSpringに要求すると、Springはアプリケーションの存続期間中にそのコンストラクターを1回だけ呼び出します。

通常、Springを使用している場合は、Springのみを使用してインスタンスを作成する必要があり、クラスのパブリックコンストラクターを持つことができます。ただし、コンストラクターがプライベートでない場合、Springをバイパスすることによって、クラスの新しいインスタンスを直接作成することを実際に妨げているわけではありません。

本当にクラスの単一インスタンスが必要な場合、アプリケーションでSpringを使用し、Springでクラスをシングルトンとして定義しても、シングルトンパターンを使用してクラスを実装する唯一の方法です。これにより、Springを使用してインスタンスを取得する場合でも、Springをバイパスする場合でも、単一のインスタンスが存在することが保証されます。


13

コンテナごと、豆ごと」は理解しにくいと思います。私は「コンテナ内のBean IDごとに1つのBean」と言います。それを理解するための例があります。Beanクラスのサンプルがあります。次のように、このクラスから2つのBeanをBean定義で定義しました。

<bean id="id1" class="com.example.Sample" scope="singleton">
        <property name="name" value="James Bond 001"/>    
</bean>    
<bean id="id7" class="com.example.Sample" scope="singleton">
        <property name="name" value="James Bond 007"/>    
</bean>

したがって、IDが「id1」のBeanを取得しようとすると、Springコンテナは1つのBeanを作成し、それをキャッシュして、id1で参照されていた場所と同じBeanを返します。id7で取得しようとすると、Sampleクラスから別のBeanが作成され、id7で参照するたびに同じBeanがキャッシュされて返されます。

これは、シングルトンパターンでは起こりそうにありません。シングルトンパターンでは、クラスローダーごとに1つのオブジェクトが常に作成されます。ただし、Springでは、スコープをシングルトンとして作成しても、コンテナーがそのクラスから多くのインスタンスを作成することは制限されません。同じIDの新しいオブジェクトの作成を再び制限するだけで、同じIDのオブジェクトが要求されたときに以前に作成されたオブジェクトを返します参照


よく説明しました。ありがとう!
Swapnil

12

Springのシングルトンスコープは、このBeanがSpringによって1回だけインスタンス化されることを意味します。プロトタイプスコープ(毎回新しいインスタンス)、リクエストスコープ(リクエストごとに1回)、セッションスコープ(HTTPセッションごとに1回)とは対照的です。

シングルトンスコープは、技術的にはシングルトンデザインパターンとは関係ありません。Beanをシングルトンスコープに配置するために、Beanをシングルトンとして実装する必要はありません。


1
私が間違っている場合は修正してください。シングルトンとしてオブジェクトを実装する必要がある場合は、シングルトンパターンを実装する必要がないので、それに従ってください。Springを使用してそのBeanを作成すると機能します。私は、Springフレームワークのシングルトンデザインパターンとシングルトンスコープに関連する私の理解と少し混乱しています。
Peeyush

1
Springでは、シングルトンパターンを使用する必要はありません。
lexicore 2010

2

SpringのシングルトンBeanとシングルトンデザインパターンに基づくクラスはかなり異なります。

シングルトンパターンは、SpringシングルトンBeanのスコープが「Beanごとのコンテナーごと」として記述されているクラスローダーごとに、特定のクラスのインスタンスが1つだけ作成されることを保証します。Springのシングルトンスコープは、このBeanがSpringによって1回だけインスタンス化されることを意味します。Springコンテナは、Beanを取得する後続の呼び出しで同じインスタンスを何度も返すだけです。


13
あなたは「ジャワ・マーベリック」ですよね?それはあなたの声明を「あなたは自分のウェブサイトにリンクしていることを隠そうとする不正な試みです。とにかく、あなたのリンクは答えにとって重要ではないようです。回答がスパムとして削除されるのを避けるため、削除します。ウェブサイトへのリンクを投稿する前に、自己宣伝に関するFAQをお読みください。また、あなたのウェブサイトへのリンクをあなたのプロフィールに入れるのはとても良いことです。
Andrew Barber、

2

2つの間に非常に基本的な違いがあります。シングルトン設計パターンの場合、クラスローダーごとに1つのクラスのインスタンスのみが作成されますが、IoCコンテナーごとに特定のIDの共有Beanインスタンスが1つ作成されるので、Springシングルトンの場合はそうではありません。

たとえば、「SpringTest」という名前のクラスがあり、XMLファイルが次のようになっているとします。

<bean id="test1" class="com.SpringTest" scope="singleton">
        --some properties here
</bean>    
<bean id="test2" class="com.SpringTest" scope="singleton">
        --some properties here   
</bean>

したがって、メインクラスで上記の2つの参照を確認すると、Springのドキュメントに従ってfalseが返されます。

Beanがシングルトンの場合、Beanの共有インスタンスは1つだけ管理され、そのBean定義に一致する1つまたは複数のIDを持つBeanに対するすべての要求は、Springコンテナによって返されるその特定のBeanインスタンスになります。

したがって、私たちの場合と同様に、クラスは同じですが、提供したIDが異なるため、2つの異なるインスタンスが作成されます。


1

春の「シングルトン」はBeanファクトリのインスタンスを取得してからキャッシュします。どのシングルトン設計パターンが厳密であるか、インスタンスは静的getメソッドからのみ取得でき、オブジェクトはパブリックにインスタンス化できません。


1

例:「Beanごとのコンテナごと」。

        <bean id="myBean" class="com.spring4hibernate4.TestBean">
            <constructor-arg name="i" value="1"></constructor-arg>
            <property name="name" value="1-name"></property>
        </bean>

        <bean id="testBean" class="com.spring4hibernate4.TestBean">
            <constructor-arg name="i" value="10"></constructor-arg>
            <property name="name" value="10-name"></property>
        </bean>
    </beans>



    public class Test {

        @SuppressWarnings("resource")
        public static void main(String[] args) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml");
            TestBean teatBean = (TestBean) ac.getBean("testBean");
            TestBean myBean1 = (TestBean) ac.getBean("myBean");
            System.out.println("a : " + teatBean.test + " : "   + teatBean.getName());
            teatBean.setName("a TEST BEAN 1");
            System.out.println("uPdate : " + teatBean.test + " : "  + teatBean.getName());
            System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName());
            myBean1.setName(" a1 TEST BEAN 10");
            System.out.println("a1 update : " + teatBean.test + " : " + myBean1.getName());
        }
    }

public class TestBean {
    public int test = 0;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name = "default";

    public TestBean(int i) {
        test += i;
    }
}

JAVAシングルトン:

public class Singleton {
    private static Singleton singleton = new Singleton();
    private int i = 0;

    private Singleton() {
    }

    public static Singleton returnSingleton() {

        return singleton;
    }

    public void increment() {
        i++;
    }

    public int getInt() {
        return i;
    }
}

public static void main(String[] args) {
        System.out.println("Test");

        Singleton sin1 = Singleton.returnSingleton();
        sin1.increment();
        System.out.println(sin1.getInt());
        Singleton sin2 = Singleton.returnSingleton();
        System.out.println("Test");
        sin1.increment();
        System.out.println(sin1.getInt());
    }

<bean class = "com.spring4hibernate4.TestBean"> <constructor-arg name = "i" value = "1"> </ constructor-arg> <property name = "name" value = "1-name"> </プロパティ> </ bean> <bean class = "com.spring4hibernate4.TestBean"> <constructor-arg name = "i" value = "10"> </ constructor-arg> <property name = "name" value = "10 -name "> </ property> </ bean> </ beans>
Hariprasad

1

スプリングシングルトンBeanは、「Beanごとのコンテナごと」と表現されます。Springのシングルトンスコープは、同じメモリ位置にある同じオブジェクトが同じBean IDに返されることを意味します。同じクラスの異なるIDの複数のBeanを作成すると、コンテナーは異なるオブジェクトを異なるIDに返します。これは、キーがBean IDで、値が1つのSpringコンテナ内のBeanオブジェクトであるキー値マッピングに似ています。シングルトンパターンは、クラスローダーごとに特定のクラスのインスタンスが1つだけ作成されることを保証します。


1

これまでのすべての答えは、少なくとも、デザインパターンとSpringシングルトンの違いを説明することに集中しており、実際の質問に対処しないでください。シングルトンデザインパターンを使用すべきですか、それともSpringシングルトンBeanですか?何が良いですか?

答える前に、あなたが両方を行うことができることを述べさせてください。Beanをシングルトンデザインパターンとして実装し、Springを使用して、それをSpringシングルトンBeanとしてクライアントクラスに挿入できます。

さて、質問への答えは簡単です。シングルトン設計パターンを使用しないでください!
パブリックコンストラクターを持つクラスとして実装されたSpringのシングルトンBeanを使用します。
どうして?シングルトンデザインパターンはアンチパターンと見なされているためです。ほとんどの場合、テストが複雑になるためです。(そして、Springを使用してインジェクトしない場合、シングルトンを使用するすべてのクラスがそれに密接にバインドされます)。また、それを置換または拡張することはできません。「Singleton anti-pattern」をグーグルして、これに関する詳細情報を取得できます。たとえば、Singleton anti-pattern

Springシングルトンの使用は、シングルトンBeanをシングルトン設計パターンとして実装するのではなく、パブリックコンストラクターを使用して実装する方法です。これにより、SpringシングルトンBeanは簡単にテストでき、それを使用するクラスは密接に結合されません。ではなく、Springがシングルトンを(インターフェースとして)必要なすべてのBeanに注入します。シングルトンBeanは、それを使用するクライアントクラスに影響を与えることなく、いつでも別の実装に置き換えることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.