Scope ‘request’ is not active for the current thread

に回答がありますが、自分なりのまとめ。

CDIと異なり、SpringのDIは、

  • デフォルトではSingleton、つまりアプリケーションスコープ。
  • デフォルトではインジェクションするインスタンスはnewされたもの。(CDIではプロキシオブジェクト)

つまり、あるオブジェクト(A)を生成する際、そのオブジェクトにインジェクトするオブジェクト(B)も生成する必要があるので、BはAより長い寿命を持っていないといけない。そしてデフォルトではAはシングルトンなのでBもシングルトンでなければならない、ということです。

@Component // シングルトン
class A {
    @Autowired // シングルトン
    private B b;
}

ここで、 B がシングルトンでない場合、このままではインジェクトできないので何らかの修正が必要になります。

  • 実オブジェクトでなくプロキシオブジェクトをインジェクトしておく
  • Aのスコープを狭める(ここではrequestスコープ以下にする)

(補足: 冒頭リンク先ではコメント欄にこれ以外の方法も書かれています)

このうち前者は問題を複雑化させる可能性があるのではと考えます。
本来requestスコープ外の場所にもインジェクションできてしまう、そして通常はHTTPリクエストが起点になるので正しく動いてしまいます。
が、例えばunit testコードを書こうとするとrequestスコープ外なのでうまくいかない、そして理由もわからない、ということに。

それよりは、各コンポーネントの本来あるべきスコープを考えたほうが良さそうです。
RestControllerはシングルトンで良いでしょうか。自分はrequestスコープが妥当であると考えます。そうするとBはインジェクションできるクラス、ということになります。
DDDでいうところのサービスはどうでしょう。これはシングルトンで良いと思います。とすると、Bをインジェクションしては駄目な場所です。

1件のコメント

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です