Edited at

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


環境


  • 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