【Spring】Spring FrameworkのサーブレットフィルタでDIを実現する

Spring FrameworkにおけるDI

Spring FrameworkでDIを実現するには、設定クラスでBeanを定義してDIコンテナにBeanを登録する必要があります。
DIコンテナに登録したBeanは、ApplicationContextインターフェースを経由して取得することができます。

やりたいこと

通常、サーブレットフィルタ(javax.servlet.Filter)はサーブレットや静的リソースへのアクセス前後に共通処理を行う際に使われますが、ApplicationContextインターフェースを経由しないため、DIコンテナに登録したBeanを取り出すことができません。
そこで、サーブレットフィルタでDIを実現すべく、実装方法を調査するのが本記事の目的となります。

前提

  • Java:Java11
  • Spring Framework:5.2.2
  • Spring Security:5.2.1

実装

いきなり答え合わせですが、web.xmlにてDelegatingFilterProxyをサーブレットフィルタとして定義した上で、対象フィルタ(ここではSampleFilter)のBean名を<filter-name>に指定すればOKです。
これでSampleFilterでDIが可能となり、@Autowiredや@Injectが使えるようになります。

・web.xml

     <filter>
        <filter-name>sampleFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>sampleFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

・SampleFilter.java

@Component("sampleFilter")
public class SampleFilter extends GenericFilterBean {
    // 略
}

解説

サーブレットフィルタをweb.xmlで定義する場合、通常だと下記のように<filter-class>にフィルタのパッケージを直接指定します。

     <filter>
        <filter-name>sampleFilter</filter-name>
        <filter-class>○○.○○.sampleFilter</filter-class>
    </filter>

しかし、パッケージ直接指定の場合はサーブレットフィルタでDIを実現できない問題が生じるため、どうにかしてDIを実現する形に持っていきたいわけです。
そこで、この問題を打開すべく、パッケージ直接指定ではなく、DelegatingFilterProxyを指定する形式に変えます。

     <filter>
        <filter-name>sampleFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

DelegatingFilterProxyについて、Qiitaの記事では以下のように解説されています。

DelegatingFilterProxy は、自身の に設定された名前を使って Spring コンテナから javax.servlet.Filter を実装した Bean を取得する。
そして、その Bean に処理を委譲するだけのサーブレットフィルタになっている。

出典:Qiita「Spring Security 使い方メモ 基礎・仕組み」

つまり、DelegatingFilterProxyがweb.xmlとApplicationContextインターフェースの橋渡し役となり、<filter-name>に設定したBeanに処理を移譲することで、サーブレットフィルタでDIを実現することを可能としているわけです。

所感

要件を満たすべく、調査含め丸二日程ハマりました。
ただ、サーブレットフィルタでDIする機会は今後もありそうなので、余裕ある時期に実装できて逆によかったのかもしれない。。

参考

Spring Security 使い方メモ 基礎・仕組み
https://qiita.com/opengl-8080/items/c105152c9ca48509bd0c