3

私の知る限り、Spring Bean はデフォルトでシングルトンです。

私が望むのは、インスタンス属性を考慮してBeanをスレッドセーフにすることです。簡単な例を使って説明します。
次のコードを検討してください。

@Controller
public class MyServlet {

    @Autowired
    private HelloService service;

    @RequestMapping(value="/hello", method = RequestMethod.GET)
    public void sayHello(HttpServletRequest req, HttpServletResponse res) throws IOException {
        service.doStuff();
    }

}


public class HelloService {

    private int i = 1;

    public void doStuff() {
        System.out.println("Started " + i);
        i++;
        System.out.println(Thread.currentThread().getName() + " Done " + i);
    }
}

出力は次のようになります。

32911580@qtp-28064776-0 - Started 1
7802158@qtp-28064776-2 - Started 2
32911580@qtp-28064776-0 - Done 3
7802158@qtp-28064776-2 - Done 3

これは、「i」変数が複数のスレッド間で共有されていることを証明しています。

このように、HelloService Bean をプロトタイプとして定義することも試みました。

<bean id="helloService" class="my.package.HelloService" scope="prototype" />

しかし、結果は同じです。

これを解決するために私が見つけた唯一の方法は次のとおりです。-宣言をdoStuff()メソッドに移動しますが、それは私が望むものではありません-doStuff()メソッドを作成しますが、これはロックがあることを意味します

私が望むのは、すべての呼び出しで HelloService の新しいインスタンスを持つことです。

誰でも私を助けることができますか?前もって感謝します。

アップデート

ルックアップメソッドを使用したメソッドインジェクションで解決策を見つけました。 http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/beans.html#beans-factory-lookup-method-injection

4

3 に答える 3

3

MyServlet のインスタンスは 1 つしかないため、HelloService のインスタンスも 1 つしかありません。

次のスプリング スコープのいずれかが役立ちます。 request 各 HTTPリクエスト の新しいインスタンス。 session サーブレット コンテナーで作成された新しい HttpSession ごとのクラスの新しいインスタンス。

これにより、コードのセマンティクスが変更されます。スコープ リクエストで Bean を宣言すると、カウンターは常に 1 になります。

ロックなしで一意のカウンターを 1 つ持つには、java.util.concurrent.atomic.AtomicInteger を使用できます。

反対側では、ロックについて悪いことは何もありません。極端な場合を除いて、ほとんどの場合、パフォーマンスへの影響は無視できます。

アプリケーションをビルドしたら、 http: //vmlens.comで競合状態を確認してください。

于 2013-10-24T07:02:56.907 に答える