2011-09-29 1 views
8

私は毎晩自分のメールサーバーをポーリングするSpring Beanを宣言しました。メールがある場合は、メールを取り出し、添付ファイルを抽出しようとします。これらのファイルはアップロード者に送信され、安全に保管されます。アップローダはSpring Beanとして宣言されています。 3番目のBeanは、電子メールの送信者をファイルのファイル名に関連付けてDBに格納します。デフォルトのBeanスコープをシングルトンとして使用すると、同時呼び出しが発生すると悪くなることはありませんか?

同時にいくつかの人が電子メールを送信しようとしたときに、一気に厄介なことが起こったことが判明しました。 DBのレコードに間違ったファイル名があります。ファイル名がまったく得られなかった人もいます。

この問題は、デフォルトでBeanのスコープがシングルトンになっているという結果に起因しています。これは、スレッドの束がおそらく1つの同じインスタンスを同時に混乱させていることを意味します。問題はこれを解決する方法です。

すべての機密方法を同期させると、すべてのスレッドがスタックしてお互いを待つことになります。これは、マルチスレッドの考え方全体には一種です。どちらかの本当に良いではありませんそれらのそれぞれの新しいインスタンスを作成しようとしている「要求」に豆をスコープ一方

、我々はメモリの消費量、およびスレッドのスケジューリング

について話す場合私は混乱している。私は何をすべきか?

+0

あなたのメソッドを同期する必要がありますが、もっと重要なこと呼び出されたメソッドが他のスレッドが依存するインスタンスデータを変更していないことを確認する必要があります。私はあなたのコードを提供していないので推測していますが、おそらく単純なメソッドの同期以上のものです。データを上書きするというシステム上の問題があるようです。 –

答えて

8

@Bozhoと@stivioの両方の回答に同意します。

シングルトンスコープのBeanに状態を格納せずに渡したり、コンテキストオブジェクトをメソッドに渡したり、処理サイクルごとに作成されるプロトタイプ/要求スコープBeanを使用することをお勧めします。これらのアプローチの1つを選択することで、通常は同期を回避することができ、デッドロックを回避しながらパフォーマンスを大幅に向上させることができます。静的メンバーのような共有状態を変更していないことを確認してください。

各アプローチの長所と短所があります。

  1. Singlton豆は、いくつかの良いオブジェクト指向設計ではありませんと言うかもしれサービスのようなクラスとして行動しています。
  2. 長い連鎖のメソッドにコンテキストを渡すと、コードが面倒になることがあります。
  3. プロトタイプBeanは、意図したよりも長い間メモリを大量に保持することがあり、メモリが枯渇する可能性があります。これらの豆のライフサイクルに注意する必要があります。
  4. プロトタイプの豆があなたのデザインをより綺麗にするかもしれません。しかし、複数のスレッドでBeanを再利用していないことを確認してください。

私は、ほとんどの単純なケースでサービスアプローチをとる傾向があります。これらのシングルトンBeanに、計算の状態を保持できる処理オブジェクトを作成させることもできます。これは、より複雑なシナリオに最適なソリューションです。

編集:あなたがBeanをスコープのプロトタイプに応じて、シングルトンBeanを持っている、とあなたは、各メソッド呼び出しのためのプロトタイプBeanの新しいインスタンスをしたい時に例があります 。 Springはそのためのいくつかのソリューションを提供しています:

最初はMethod Injectionを使用しています。私はあなたのクラスを抽象的に強制するので、このアプローチが本当に好きではありません。

ServiceLocatorFactoryBean、または独自のファクトリクラス(依存関係を挿入してコンストラクタを呼び出す必要があります)を使用します。このアプローチは、ほとんどの場合、本当にうまく動作し、あなたをSpringと結びつけません。

プロトタイプBeanに実行時依存性を持たせたい場合もあります。私の良き友人はここに良い投稿を書いています:http://techo-ecco.com/blog/spring-prototype-scoped-beans-and-dependency-injection/

+0

私はあなたに同意し、ポイント1を除いてupvotedです。シングルトンBeanは単体テストをより困難にし、マジックの依存関係を導入するため推奨されませんが、私たちはJava Singleton、プライベートコンストラクタと静的メソッドインスタンスを返すスプリングシングルトンにはこれらの問題はありません。 – stivlo

+0

@stivio私がシングルトンの豆を書いたとき、私はシングルトンの範囲で春の豆を意味し、シングルトンのデザインパターンを実装するJavaのクラスではありませんでした。私は後でGoFの本で最も問題のパターンかもしれないことに同意しますが、シングルトンスプリングは簡単にテストすることはできません。それらをインスタンス化し、インターフェイスを導入し、依存関係を模擬することができます。他のクラスと同様にテストしてください。 –

+1

まさに、それは私が言ったことです: "春のシングルトンはこれらの問題を持っていません。" - それがポイント1に同意しない理由です。あなたがGoFシングルトンについて話していたら、私は同意します。 – stivlo

12

シングルトンスコープのBeanは、通常は問題を解決するものではありません。メソッドのパラメータとしてのみデータを渡し、それをフィールドに割り当てない場合は、安全です。

2

それ以外の場合は、Beanをリクエストとして宣言するだけで、メモリ消費について心配する必要はありません。ガベージコレクションでは十分なメモリがある限り、パフォーマンス上の問題はありません。

+0

私の唯一の問題は、Spring Integrationのservice-activatorを使用してメールをポーリングしている、つまり実際にはWebリクエストがないため、MailManagerのスコープを「リクエスト」にできないことです。私はまだMailManagerを「スレッドごとに」マークすることはできますか? – user802232

+0

は「プロトタイプ」を使用します。 – stivlo

+0

SpringコアのSimpleThreadScope(http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/context/support/SimpleThreadScope.html)を使用して、Beanをスレッドにバインドすることもできます-Local –

1

シングルトンはステートフルでスレッドセーフである必要があります。

シングルトンがステートレスである場合、ステートフルな縮退ケースであり、スレッドセーフであることは自明です。しかし、シングルトンのポイントは何ですか?誰かがリクエストするたびに新しいものを作成してください。

インスタンスがステートフルで、スレッドセーフでない場合は、シングルトンであってはなりません。各スレッドは排他的に異なるインスタンスを持つ必要があります。

+1

私はステートフルなシングルトンはかなり危険だと思っています(事実上グローバル変数です)。なぜシングルトンはステートフルでなければならないと思いますか? – sleske

2

抽象的な言い方をすれば、あなたがSpring Integrationを使用している場合、メッセージ自体の観点からコードを構築する必要があります。たとえば、すべての重要な状態にメッセージを伝播する必要があります。これにより、より多くのSpring Integrationインスタンスを追加して負荷を処理することで、スケールアウトが簡単になります。 Spring統合の唯一の状態(本当に)は、アグリゲータのようなコンポーネントであり、アキュレートを持つメッセージを待って収集します。この場合、MongoDBのようなバッキングストアに委譲してこれらのメッセージの格納を処理することができます。もちろんスレッドセーフです。

より一般的には、これはステージングドリブン型アーキテクチャの例です。コンポーネントはメッセージを処理するにはステートレスに(N(1))メッセージを処理し、チャネル上に転送して、メッセージが来た前のコンポーネントについて。

あなたは春の統合を使用してスレッドの安全性の問題が発生した場合、あなたは少し違った意図よりも何かをやっている可能性があり、それはあなたのアプローチを再訪する価値があるかもしれません...

関連する問題