#目的
- 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
が登録を行っているがFilterRegistrationBean
とFilter
で登録は別々に行われる。
FilterRegistrationBean
=> Filter
という順番で取りあえず格納される。
そののちOrder要素に沿ってソートされる。
ソートはOrderの番号に従って整列されるのが前提であるが、Orderが被った場合は下記の順番で並ぶ
-
FilterRegistrationBean
=>Filter
- 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が適用される。