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

Spring Bootでサーブレットフィルターを使う [Spring Boot 1.x, 2.x両対応]

More than 1 year has passed since last update.

環境

  • Spring Boot 1.5.10
  • Embedded Tomcat 8.5.27
  • JDK 8

2018-03-09追記
Spring Boot 2.0.0.RELEASEにアップグレードしても同様の挙動でした。

2018-12-20追記
Spring Boot 2.1の説明を追記しました。

基本的なFilterの登録方法

Spring Bootで用意されているFilterRegistrationBeanクラスを利用します。
FilterRegistrationBeanをBean定義すると、Spring BootのAuto Configurationクラス内でFilterが取り出され、Embedded Serverに登録されます。

@Configuration
public class SomeConfig {

    @Bean
    public FilterRegistrationBean hogeFilter() {
        // FilterをnewしてFilterRegistrationBeanのコンストラクタに渡す
        FilterRegistrationBean bean = new FilterRegistrationBean(new HogeFilter());
        // Filterのurl-patternを指定(可変長引数なので複数指定可能)
        bean.addUrlPatterns("/*");
        // Filterの実行順序。整数値の照準に実行される
        bean.setOrder(Integer.MIN_VALUE);
        return bean;
    }

    @Bean
    public FilterRegistrationBean fugaFilter() {
        FilterRegistrationBean bean = new FilterRegistrationBean(new FugaFilter());
        bean.addUrlPatterns("/*");
        // HogeFilterの後に実行される
        bean.setOrder(Integer.MIN_VALUE + 1);
        return bean;
    }

    // 何個でもFilterを定義可能
}

Filter内で他のBeanを使う

@Beanメソッドは、引数で他のBeanを受け取ることができます。これは、もともとSpringが持っている機能です。
引数で受け取ったBeanを、Filterのコンストラクタなどで受け取ればOKです。

public class HogeFilter extends OncePerRequestFilter { // もちろん「implements Filter」でもOK
    private final FugaBean fugaBean; // フィールドを作成

    public HogeFilter(FugaBean fugaBean) { // コンストラクタでBeanを受け取る
        this.fugaBean = fugaBean;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // 前処理をここに書く
        chain.doFilter(request, response);
        // 後処理をここに書く
    }
}
@Configuration
public class HogeConfig {

    @Bean
    public FilterRegistrationBean hogeFilter(FugaBean fugaBean) {
        // FilterのコンストラクタにBeanを渡す
        FilterRegistrationBean bean = new FilterRegistrationBean(new HogeFilter(fugaBean));
        // ...
        return bean;
    }
}

FugaBeanは、他のどこか(他のConfigクラスやコンポーネントスキャンなど)でBean定義されている必要があります。

Filter自体はBeanではないので注意してください。つまり、@AutowiredでFilterにBeanをDIしたり、AOPをFilterに適用したりすることはできません。

全Filterの適用順序を一覧で見る

FilterRegistrationBeanからFilter取り出し・Embedded Serverへの登録を行っているのは、ServletContextInitializerBeansというクラスです。このクラスのDEBUGログ(注: Spring Boot 2.1以降はTRACEログ)を出力すればOKです。
orderの値の昇順にFilterが実行されます。

application.properties
# Boot 2.1以降は、debugではなくtraceにする
logging.level.org.springframework.boot.web.servlet.ServletContextInitializerBeans=debug
標準出力
...
2018-02-28 11:58:37.611 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Added existing Filter initializer bean 'loggingFilter1'; order=-2147483648, resource=com.example.Application
2018-02-28 11:58:37.611 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Added existing Filter initializer bean 'loggingFilter2'; order=-2147483647, resource=com.example.Application
2018-02-28 11:58:37.612 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Added existing Filter initializer bean 'loggingFilter3'; order=-2147483646, resource=com.example.Application
2018-02-28 11:58:37.612 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Added existing Servlet initializer bean 'dispatcherServletRegistration'; order=2147483647, resource=class path resource [org/springframework/boot/autoconfigure/web/DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration.class]
2018-02-28 11:58:37.638 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'characterEncodingFilter'; order=-2147483648, resource=class path resource [org/springframework/boot/autoconfigure/web/HttpEncodingAutoConfiguration.class]
2018-02-28 11:58:37.638 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'hiddenHttpMethodFilter'; order=-10000, resource=class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.class]
2018-02-28 11:58:37.638 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'httpPutFormContentFilter'; order=-9900, resource=class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.class]
2018-02-28 11:58:37.638 DEBUG 4323 --- [ost-startStop-1] o.s.b.w.s.ServletContextInitializerBeans : Created Filter initializer for bean 'requestContextFilter'; order=-105, resource=class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]
...

Filter自体をBean定義すると?

Filter自体をBean定義してもOKなのですが、url-patternや実行順序を指定できません。@Beanメソッドに@Orderアノテーションを指定しても無視されるようです(@Orderの値に関わらず、ログに出力されるorderの値が2147483647になります)。

    @Bean
    @Order(Integer.MIN_VALUE) // この値は無視されるっぽい(仕様かどうかは不明)
    public HogeFilter hogeFilter() {
        return new HogeFilter();
    }

ということで、FilterRegistrationBeanを使いましょう。

参考資料

Spring Boot Reference
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners-beans
Javadoc
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/web/servlet/FilterRegistrationBean.html

suke_masa
Java / Spring / Microservices / Kubernetes(CKAD) / IntelliJ IDEA
https://www.casareal.co.jp/ls
casareal
システム開発/評価・検証支援/品質改善支援サービスと現場に即した実践的なIT研修サービスを提供しています。
https://www.casareal.co.jp/
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