36

Spring を使用する場合、コンポーネント クラス ( @Controller@Service@Repository) はスレッド セーフである必要がありますか? それとも、Spring はそれらをスレッドセーフな方法で使用するので、スレッドセーフについて心配する必要はありませんか?

つまり、 に@RequestMappingメソッドがある場合@Controller、そのメソッドを複数のスレッドから同じコントローラー オブジェクトに対して同時に呼び出すことができるでしょうか?

(これは以前に尋ねられましたが、そのようには回答されていません)。

4

4 に答える 4

55

与えられた

@Controller
public class MyController {
    @RequestMapping(value = "/index")
    public String respond() {
        return "index";
    }
}

Spring は のインスタンスを作成しますMyController。これは、Spring が構成を解析し、<mvc:annotation-driven>(の@Controllerように@Component) を参照し、注釈付きクラスをインスタンス化するためです。それも見るので@RequestMapping、そのための を生成します。こちらのドキュメントHandlerMappingを参照してください。

が受信するすべての HTTP 要求は、登録済みの beforeDispatcherServletを介してこのコントローラー インスタンスにディスパッチされ、そのインスタンスの Java リフレクションを介して呼び出されます。HandlerMappingrespond()

次のようなインスタンスフィールドがある場合

@Controller
public class MyController {
    private int count = 0;
    @RequestMapping(value = "/index")
    public String respond() {
        count++;
        return "index";
    }
}

count多くのスレッドによって変更される可能性があり、変更が失われる可能性があるため、危険です。

サーブレット コンテナの仕組みを理解する必要があります。コンテナーは、Spring MVC の 1 つのインスタンスをインスタンス化しますDispatcherServlet。コンテナは、接続に応答するために使用するスレッドのプールも管理します。HTTP リクエスト。そのようなリクエストが到着すると、コンテナーはプールからスレッドを選択し、そのスレッド内で、 Spring が (構成から) 登録した正しいインスタンスにディスパッチするservice()メソッドを実行します。DispatcherServlet@Controller

はい、Spring MVC クラスはスレッドセーフでなければなりません。これを行うには、クラス インスタンス フィールドのさまざまなスコープを試すか、代わりにローカル変数を使用します。それができない場合は、コード内の重要なセクションの周りに適切な同期を追加する必要があります。

于 2013-05-28T15:13:44.080 に答える
-1

はい、もちろん。

それらがデフォルトでスレッドセーフになるステートレスであることが最善です。共有された変更可能な状態がない場合、問題はありません。

于 2013-05-28T15:03:34.767 に答える
-1

基本的に、答えはイエスとノーでなければなりません。非常に深刻な理由を除いて。Spring の同期が機能するからではありません (デフォルトでは、コントローラーはシングルトン Bean です)。大まかに言えば、メソッド呼び出しに沿ってスレッドセーフを維持する必要がありますが、通常、サーブレットのメカニズムは、スレッド内でリクエストが実行されるため、何かを同期する必要性を一掃します。そのため、 @RequestMapping アノテーション付きメソッドの呼び出し中に、呼び出しスタック全体が 1 つのスレッドで実行されました。ルートでは、サーブレットの service-do(Get, Post..) メソッドから発信され、Spring が構築するハンドラー マップが動作します ( http://www.studytrails.com/frameworks/spring/spring-mvcを参照)。 -handler-mappings/ http://technicalstack.com/dispatcher-servlethandlermapping-controller/例えば)。URL が解決された後、Spring はハンドラーのマップから処理メソッドを呼び出します。他のトリックはありません。したがって、DispatchServlet のインスタンス メソッドの doPost(...) 内で作業するとします。サーブレットスレッドは安全ですか? 粗いのない。スレッドセーフにできますか?ロックを使用し、同期し、他に何を使用して、サーブレットをボトルネックにしますか?まったく同じことがコントローラーについてです。Servlet の doGet/Post/what else メソッドは基本的に機能モデルを持ち、すべてのデータは HttpServletRequest オブジェクトにあります。コントローラ オブジェクトで使用されるデータ クラスで同じ方法を使用し、フィールドの代わりにスタックする必要があります。それらへのアクセスを同期できますが、ボトルネックの代償を払う必要があります。大まかに言えば、アトミックを使用できますが、それはそれほど必要ですか? セッション中に状態を維持する必要がある場合は、 @Scope("session" を使用できます ) @Controller の後、または (シングルトン コントローラーの場合) 署名付きのハンドラー メソッド (..., HttpSession) の両方に長所と短所があります。ただし、追加の CPU と GC の費用を作成したことに注意してください。とにかく、フィールドを使用してステートレスの概念から抜け出したい場合は、コントローラーのスレッドセーフを担当します。通常、クライアントの状態を保持するには、キャッシュ (たとえば、redis) が適しています。少なくとも、障害が発生したときの状態を復元できます。セッション スコープ外のステートフル コントローラーには、基本的に理由はありません。少なくとも、障害が発生したときの状態を復元できます。セッション スコープ外のステートフル コントローラーには、基本的に理由はありません。少なくとも、障害が発生したときの状態を復元できます。セッション スコープ外のステートフル コントローラーには、基本的に理由はありません。

于 2018-02-14T13:08:54.220 に答える