Spring @RequestScopeや@SessionScopeはどこに保存されるのか?我々は真相に迫った

ある日の出来事

SpringのBeanのスコープ、便利ですよね。ライフサイクル管理を任せられるのはDIコンテナを利用するメリットの大きなところだと思います。

いつも私は、何も考えずに以下のようにコーディングして、Springコンテナにスコープ管理を任せていました。

@Component
@SessionScope
public class User implements Serializable {}

そしてある日、ふと疑問が…このBeanって結局どこに格納されてるんだろう…@SessionScopeっていうくらいだからセッションに格納される?

結論

実行環境がServletの場合、

  • @SessionScopeはHttpSessionに格納される
  • @RequestScopeはHttpServletRequestに格納される

Spring WebFluxの場合、@SessionScope@RequestScopeはサポートされていない。いずれもスレッドローカルに値を管理する仕組みであり、実行スレッドが固定されない環境では実現が難しいため。
参考 stack overflow

我々は真相に迫った

検証環境

pom.xml

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
                ..
    <\dependencies>

まずはデバッグ

アノテーションはただのマーカーなので、実際にアノテーションを処理するクラスを探したい。しかし、アノテーション自体にはブレークポイントが打てないため、探すのがけっこう難しい。そのため、まずはHttpSession#setAttribute(String name, Object value)にあたりを付けて、ブレークポイントを打ってみた。

そうすると、以下のスタックトレースが取得できた。

f:id:kimulla:20191201215029p:plain

うーん、SessionScopeクラスがあやしそう

Javadocを読んでみる

SessionScope(@SessionScopeとは違うパッケージの)はScopeインタフェース(@Scopeとは違う)を実装したクラスのひとつ。 またScopeインタフェースは、データのCRUD操作を定義している。
参考 SessionScope Javadoc
参考 Scope Javadoc

ソースコードを読んでみる

Scopeは4つのメソッドを持っている。

public interface Scope {
  Object get(String name, ObjectFactory<?> objectFactory);
  Object remove(String name);
  Object resolveContextualObject(String key);
  String getConversationId();
}

Scope#getの実装はAbstractRequestAttributesScope#getで以下のように定義されている。
参考 AbstractRequestAttributesScope#get

永続先への具体的な操作はRequestAttributesクラスで行われる。デバッグしてみたら実装クラスにはServletRequestAttributesが利用されていた。

ServletRequestAttributesを確認すると、HttpSession#setAttributeを呼んでいた。
参考 ServletRequestAttributes

@RequestScopeも似た処理で、書き込み先はHttpServletRequestだった。

終わりに

Springの@RequestScope@SessionScopeはどこから来てどこへ行くのか?我々は真相に迫ったが、あまり驚きはなかった。また、調べたことがそのままspringのリファレンスに書いてあった。リファレンスしっかり読もう…(反省)
参考 1.5.5. Custom scopes