LoginSignup
7
10

More than 3 years have passed since last update.

SpringBootのFilter適用順

Posted at

目的

  • SpringBootで利用されるFilterについて主に適用順に関して細かい所まで見ていく

前提知識

  • FilterはFilterRegistrationBeanでラップしてBean登録すると順番や適用URLなどを設定できる
  • Orderedインターフェースを実装しても順番をコントロールできる
  • Filterを直接Bean登録すると一番最後に適用される
  • AutoConfigureでデフォルトで登録されるfilter類がいくつかある

疑問点

  • Orderがかち合った場合はどうなるのか?
  • Requestが来た時にどのようにFilterが展開されるのか

検証

Requestが来た時にどのようにFilterがセットされるか?

  • ApplicationFilterFactoryがFilterChainを作成している
ApplicationFilterFactory.java
public static ApplicationFilterChain createFilterChain(ServletRequest request,
            Wrapper wrapper, Servlet servlet) {

        //省略

        // Acquire the filter mappings for this Context
        StandardContext context = (StandardContext) wrapper.getParent();
        FilterMap filterMaps[] = context.findFilterMaps();

        // If there are no filter mappings, we are done
        if ((filterMaps == null) || (filterMaps.length == 0))
            return filterChain;

        // Acquire the information we will need to match filter mappings
        DispatcherType dispatcher =
                (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

        String requestPath = null;
        Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
        if (attribute != null){
            requestPath = attribute.toString();
        }

        String servletName = wrapper.getName();

        // Add the relevant path-mapped filters to this filter chain
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersURL(filterMaps[i], requestPath))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        //省略

        // Return the completed filter chain
        return filterChain;
    }

この実装を覗いてもわかるように、Filterの適用順序自体はStandardContextから取り出した時点で決まっている。

ContextへはServletContextInitializerBeansが登録を行っているがFilterRegistrationBeanFilterで登録は別々に行われる。
FilterRegistrationBean => Filterという順番で取りあえず格納される。
そののちOrder要素に沿ってソートされる。

ソートはOrderの番号に従って整列されるのが前提であるが、Orderが被った場合は下記の順番で並ぶ

  1. FilterRegistrationBean => Filter
  2. Beanの登録順

したがって、下記のようなConfigを指定すると

FilterConfig.java
public class FilterConfig {



    @Bean
    public FilterRegistrationBean fugaFilterConfig() {
        FilterRegistrationBean bean = new FilterRegistrationBean(new FugaFilter());
        bean.setOrder(Ordered.LOWEST_PRECEDENCE);
        return bean;
    }


    @Bean
    public Filter hogeFugaFilterConfig() {
        Filter bean = new HogeFugaFilter();

        return bean;
    }

    @Bean
    public Filter hogeFilterConfig() {
        Filter bean = new HogeFilter();
        return bean;
    }
}

FugaFilter => HogeFugaFilter => HogeFilterという順でFilterが適用される。

7
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
10