Help us understand the problem. What is going on with this article?

Spring Boot 2 Filter内でSessionScopeBeanをDIする

前置き

最近Spring BootでWeb開発をしています。直接HttpSessionを利用する方法ではなく、できるだけ@SessionScopeでセッションを管理したいと思っています。Filter内で@SeesionScope Beanを参照する方法を調査しました。

構成

名前 バージョン
macOS Catalina 10.15.4
IntelliJ IDEA 2019.3.4 (Community Edition)
Java "11.0.2" 2019-01-15
Spring Boot 2.2.6
Kotlin 1.3.71

サンプルコードやプロジェクトをGitHubに公開しています。よろしければご覧ください。

結論

いろいろな情報があり調査した内容も後述しますが、最初に結論から書きます。
シンプルな構成であれば@Autowiredのみで実現可能でした。

UserInfo.kt(@SessionScope)
@Component
@SessionScope
data class UserInfo(
        var name: String?
) : Serializable
SessionFilter.kt(OncePerRequestFilter)
@Component
class SessionFilter : OncePerRequestFilter() {

    // ControllerでDIするのと同様でした。
    @Autowired
    private lateinit var userInfo: UserInfo

    override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
        println("name: ${userInfo.name}")
        filterChain.doFilter(request, response)
    }
}

結論までの経緯

Spring Boot 2の書籍ではありませんが、Spring界隈では有名と思われるSpring徹底入門 Spring FrameworkによるJavaアプリケーション開発ではDelegatingFilterProxyにフィルターを登録することをXMLで定義する方法が提案されていました。
そのため、まずDelegatingFilterProxyを使う方法を試行することにしました。筆者はXMLで定義する方法を好まないので、Java Config(Kotlin)で書き直しました。

SessionFilter.kt(OncePerRequestFilter)
@Component("SessionFilter")  // 名前を指定していました。
class SessionFilter : OncePerRequestFilter() {
    :
    : (結論で掲載したコドと同じ)
    :
}
WebInitializer.kt
class WebInitializer : AbstractAnnotationConfigDispatcherServletInitializer() {
    override fun getRootConfigClasses(): Array<Class<*>>? {
        return null
    }

    override fun getServletMappings(): Array<String> {
        return arrayOf("/")
    }

    override fun getServletFilters(): Array<Filter> {
        val dfp = DelegatingFilterProxy().apply {
            // SessionFilter.ktの@Componentで指定した名前を設定します。
            setTargetBeanName("SessionFilter")
        }
        return arrayOf(dfp)
    }

    override fun getServletConfigClasses(): Array<Class<*>>? {
        return arrayOf(WebConfig::class.java)
    }
}

FilterにDIできないFAQをいくつか拝見して、上記のような対処方法が紹介されていることがありましたが、筆者の環境では結論のとおり、この記述がなくても目的を達成しました。
Spring MVCとSpring Boot 2の違いがあるのかもしれませんが、情報が少なすぎて調査しきれていません。

終わりに

(決してマイナーなWebフレームワークではないと思いますが)他の有名なWebフレームワークと比較すると、Spring関連の情報は煩雑でレガシーなものが多いような印象を持ちました。そのため、何かのお役に立てたらいいなぁと思いまして、久しぶりに記事を投稿しました。

devnokiyo
ゲーム関連のWebサイトや時々モバイルアプリを作るエンジニアです。ご縁がありTechpitさんでプログラミング教材を執筆しました。 犬とデジモノガジェットが好きです。犬に関するWebサイトかモバイルアプリを個人開発しようとしてます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away