Spring Bootでのサーブレットフィルタ設定

引き続きSpring Bootに関する投稿です。今回は、Spring Bootでサーブレットフィルタを設定するにはどうするか?、です。

環境

  • spring-boot-2.0.4.RELEASE
  • spring-boot-starter-web
  • Embedded Tomcat 8.5.32

組み込みのTomcatコンテナで動作させる前提です。

フィルタの登録方法

Spring Bootでは、web.xmlのような設定ファイルは不要で、コントローラやフィルタなどのクラスを実装し、アノテーションやBean定義を行なうだけで、容易にSpring Bootに追加したい機能(今回はフィルタ)を認識させることができます。

さて、Spring Bootでフィルタを登録する方法ですが、1〜3で利用頻度もしくは一般的であろう順(著者感覚)に整理してみました。

1. FilterRegistrationBeanのBean定義

Spring Bootでは、Servlet、Filter、Listenerに対し、それぞれServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBeanというInitializerクラスが用意されています。

これらのクラス群は、ServletContextInitializerインタフェースを実装しており、ServletContextの初期化時に呼ばれ、各種コンフィグレーションを行なうようになっています。そして、各種BeanはServletContextInitializerBeansコンテナ(ここではコレクションのデータコンテナを意味する)に登録されており、TomcatStarteronStartupコールバックでコンフィグレーションが実行されます。

package com.example.demo;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyWebMvcConfig {

    @Bean
    public FilterRegistrationBean myWebMvcFilter() {
        // ServletContextInitializerBeansに格納される
        FilterRegistrationBean bean = new FilterRegistrationBean(new MyFilter());
        // <url-pattern/>
        bean.addUrlPatterns("/*");
        // MyFilterがMyFilter2より先に呼ばれる
        bean.setOrder(1);
        return bean;
    }

    @Bean
    public FilterRegistrationBean myWebMvcFilter2() {
        // ServletContextInitializerBeansに格納される
        FilterRegistrationBean bean = new FilterRegistrationBean(new MyFilter2());
        // <url-pattern/>
        bean.addUrlPatterns("/*");
        // MyFilterがMyFilter2より先に呼ばれる
        bean.setOrder(2);
        return bean;
    }
}

MyFilter、MyFilter2クラスは、通常のフィルタ定義と同様で、javax.servlet.Filterインターフェースを実装したクラスとして定義します。

package com.example.demo;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("do something");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() { }
}

参考 

2. FilterのBean定義

Servlet3.0で@WebFilterでフィルタ定義ができるようになりました。通常Spring Bootで組み込みコンテナを使って起動した場合、この@WebFilter定義は無視されます。しかし、これらのアノテーションを使ったクラス(ライブラリなど)をアプリケーションでもそのまま利用したい場合、@ServletComponentScanをつけると認識してくれるようです。

@ServletComponentScanを付与した場合、ServletComponentHandlerを継承している各種HandlerクラスであるWebFilterHandlerWebListenerHandlerWebServletHandlerで処理されます。@ServletComponentScanには、スキャンのベースとなるパッケージを指定します。@ServletComponentScanの指定がない場合は、アノテーションが指定されたクラスのパッケージからスキャンされます。

@Configuration
@ServletComponentScan(basePackages = "com.example")
public class MyWebMvcConfig {
   ... bean definitions etc
}

フィルタクラスに@WebFilterを指定します。

package com.example.demo;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter
public class MyFilter3 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("do something");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() { }

}

参考 

3. ServletContextInitializerのBean定義

フィルタ以外にもServletContextの初期化時に何らかの処理をしたい場合には、独自のServletContextInitializerを定義することができます。この場合1と同様、ServletContextInitializerBeansに登録され、コンテナ起動時にスタートアップコールバックが呼ばれます。コールバックの引数で、ServletContextオブジェクトが渡されるので、その中で必要な設定を行なう方法も可能だと思います。

以下は直接Servlet APIを呼んで、InitParameterやFilterを登録する例です。

package com.example.demo;

import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.springframework.boot.web.servlet.ServletContextInitializer;

@Order(Integer.MIN_VALUE)
public class MyServletContextInitializer implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        // Set init parameter
        servletContext.setInitParameter("myparam", "myvalue");

        // Register my filter
        Filter filter = servletContext.createFilter(MyFilter4.class);
        FilterRegistration filterRegistration = servletContext.addFilter("myFilter4", filter);
        filterRegistration.addMappingForUrlPatterns(null, true, "/*");
    }
}

参考 

参考リンク

byebyehaikikyou

日記やIT系関連のネタ、WordPressに関することなど様々な事柄を書き付けた雑記です。ITエンジニア経験があるのでプログラミングに関することなどが多いです。

シェアする

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

コメントする

Translate »