SpringコンテナにはデフォルトでシングルトンとしてBeanがあり、Springフレームワークに基づくWebアプリケーションがある場合、Springを通じてBeanを作成するだけでなく、グローバルデータを保持するシングルトンデザインパターンを実装する必要があります。 。
私が実際に尋ねようとしていたことを説明できない場合は、ご容赦ください。
回答:
SpringのシングルトンBeanとシングルトンパターンはまったく異なります。シングルトンパターンは、特定のクラスのインスタンスがクラスローダーごとに1つだけ作成されることを示しています。
Springシングルトンのスコープは、「Beanごとのコンテナーごと」として記述されます。これは、Spring IoCコンテナーごとの単一オブジェクトインスタンスへのBean定義のスコープです。Springのデフォルトのスコープはシングルトンです。
デフォルトのスコープはシングルトンですが、<bean ../>
要素のスコープ属性を指定することで、Beanのスコープを変更できます。
<bean id=".." class=".." scope="prototype" />
Springのシングルトンスコープは、Springコンテキストの単一のインスタンスを意味します
。Springコンテナは、Beanを取得するための後続の呼び出しで同じインスタンスを何度も返すだけです。
そして、Beanのクラスがシングルトンとしてコーディングされているかどうかにかかわらず、Springは気にしません。実際、クラスがプライベートとしてコンストラクターを持つシングルトンとしてコーディングされている場合、SpringはBeanUtils.instantiateClass(ここでは javadoc )を使用してコンストラクターをアクセス可能に設定し、呼び出しますそれ。
あるいは、次のようなBean定義でfactory-method属性を使用できます。
<bean id="exampleBean" class="example.Singleton" factory-method="getInstance"/>
最も単純な例を見てみましょう。アプリケーションがあり、デフォルトのクラスローダーを使用するだけです。何らかの理由で、アプリケーションに複数のインスタンスを含めないようにするクラスがあるとします。(数人がアプリケーションの一部で作業するシナリオを考えてください)。
Springフレームワークを使用していない場合、シングルトンパターンは、アプリケーション内にクラスのインスタンスが複数存在しないことを保証します。これは、コンストラクタがプライベートであるため、「新規」を実行してクラスのインスタンスをインスタンス化できないためです。クラスのインスタンスを取得する唯一の方法は、常に同じインスタンスを返すクラスの静的メソッド(通常は「getInstance」と呼ばれる)を呼び出すことです。
アプリケーションでSpringフレームワークを使用していると言うと、クラスのインスタンスを取得する通常の方法(クラスのインスタンスを返す新しいメソッドまたは静的メソッド)に加えて、Springに要求することもできますそのクラスとSpringのインスタンスは、シングルトンパターンを使用してクラスを作成しなかった場合でも、そのクラスのインスタンスを要求するときは常に同じインスタンスを返すことを保証します。つまり、クラスにパブリックコンストラクターがある場合でも、常にそのクラスのインスタンスをSpringに要求すると、Springはアプリケーションの存続期間中にそのコンストラクターを1回だけ呼び出します。
通常、Springを使用している場合は、Springのみを使用してインスタンスを作成する必要があり、クラスのパブリックコンストラクターを持つことができます。ただし、コンストラクターがプライベートでない場合、Springをバイパスすることによって、クラスの新しいインスタンスを直接作成することを実際に妨げているわけではありません。
本当にクラスの単一インスタンスが必要な場合、アプリケーションでSpringを使用し、Springでクラスをシングルトンとして定義しても、シングルトンパターンを使用してクラスを実装する唯一の方法です。これにより、Springを使用してインスタンスを取得する場合でも、Springをバイパスする場合でも、単一のインスタンスが存在することが保証されます。
「コンテナごと、豆ごと」は理解しにくいと思います。私は「コンテナ内の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のオブジェクトが要求されたときに以前に作成されたオブジェクトを返します。参照
Springのシングルトンスコープは、このBeanがSpringによって1回だけインスタンス化されることを意味します。プロトタイプスコープ(毎回新しいインスタンス)、リクエストスコープ(リクエストごとに1回)、セッションスコープ(HTTPセッションごとに1回)とは対照的です。
シングルトンスコープは、技術的にはシングルトンデザインパターンとは関係ありません。Beanをシングルトンスコープに配置するために、Beanをシングルトンとして実装する必要はありません。
SpringのシングルトンBeanとシングルトンデザインパターンに基づくクラスはかなり異なります。
シングルトンパターンは、SpringシングルトンBeanのスコープが「Beanごとのコンテナーごと」として記述されているクラスローダーごとに、特定のクラスのインスタンスが1つだけ作成されることを保証します。Springのシングルトンスコープは、このBeanがSpringによって1回だけインスタンス化されることを意味します。Springコンテナは、Beanを取得する後続の呼び出しで同じインスタンスを何度も返すだけです。
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つの異なるインスタンスが作成されます。
例:「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());
}
これまでのすべての答えは、少なくとも、デザインパターンとSpringシングルトンの違いを説明することに集中しており、実際の質問に対処しないでください。シングルトンデザインパターンを使用すべきですか、それともSpringシングルトンBeanですか?何が良いですか?
答える前に、あなたが両方を行うことができることを述べさせてください。Beanをシングルトンデザインパターンとして実装し、Springを使用して、それをSpringシングルトンBeanとしてクライアントクラスに挿入できます。
さて、質問への答えは簡単です。シングルトン設計パターンを使用しないでください!
パブリックコンストラクターを持つクラスとして実装されたSpringのシングルトンBeanを使用します。
どうして?シングルトンデザインパターンはアンチパターンと見なされているためです。ほとんどの場合、テストが複雑になるためです。(そして、Springを使用してインジェクトしない場合、シングルトンを使用するすべてのクラスがそれに密接にバインドされます)。また、それを置換または拡張することはできません。「Singleton anti-pattern」をグーグルして、これに関する詳細情報を取得できます。たとえば、Singleton anti-pattern
Springシングルトンの使用は、シングルトンBeanをシングルトン設計パターンとして実装するのではなく、パブリックコンストラクターを使用して実装する方法です。これにより、SpringシングルトンBeanは簡単にテストでき、それを使用するクラスは密接に結合されません。ではなく、Springがシングルトンを(インターフェースとして)必要なすべてのBeanに注入します。シングルトンBeanは、それを使用するクライアントクラスに影響を与えることなく、いつでも別の実装に置き換えることができます。