@WebFilter如何正确使用(Filter过滤器)?

2,136 阅读3分钟

1.过滤器作用在什么地方

对web发送的请求拦截进行环绕处理

image.png

2.如何编写代码

方式一

实现Filter接口,加上注解@WebFilter,根据其中的urlPatterns过滤请求。主类加上注解@ServletComponentScan,basePackages值为filter所在的包

@WebFilter(filterName = "myFilter",urlPatterns = "/path")
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
	//filter初始化的时候调用
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //请求会先到这里,然后在到controller层
	filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        //filter被销毁的收调用
        Filter.super.destroy();
    }
}

在主方法类上加上注解,包路径为filter类所在的包
@ServletComponentScan(basePackages = {})

方式二

实现Filter接口。按照以下方式加配置类。

public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
	filterChain.doFilter(servletRequest, servletResponse);
    }
}


@Configuration
public class Configuration {

    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.setUrlPatterns(Collections.singleton("/user"));
        filterRegistrationBean.setName("myFilter");
        return filterRegistrationBean;
    }
}

3.产生的问题

3.1 过滤路径不起作用

什么时候判断拦截路径?

ApplicationFilterFactory#createFilterChain()

将所有的filter取出来,筛选和requestPath符合的Filter放到filterChain中

//取所有的filter
FilterMap[] filterMaps = context.findFilterMaps();
if (filterMaps != null && filterMaps.length != 0) {
    DispatcherType dispatcher = (DispatcherType)request.getAttribute("org.apache.catalina.core.DISPATCHER_TYPE");
    String requestPath = null;
    Object attribute = request.getAttribute("org.apache.catalina.core.DISPATCHER_REQUEST_PATH");
    if (attribute != null) {
        requestPath = attribute.toString();
     }

    String servletName = wrapper.getName();
    FilterMap[] var10 = filterMaps;
    int var11 = filterMaps.length;

    int var12;
    FilterMap filterMap;
    ApplicationFilterConfig filterConfig;
    for(var12 = 0; var12 < var11; ++var12) {
        filterMap = var10[var12];
        if (matchDispatcher(filterMap, dispatcher) && matchFiltersURL(filterMap, requestPath)) {
            filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());
            if (filterConfig != null) {
                filterChain.addFilter(filterConfig);
            }
        }
    }
}

ApplicationFilterFactory#matchFiltersURL()

根据Filter中的urlPattern对请求路径进行筛选,符合条件的放到filterChain

private static boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
    if (filterMap.getMatchAllUrlPatterns()) {
        return true;
    } else if (requestPath == null) {
        return false;
    } else {
        String[] testPaths = filterMap.getURLPatterns();
        String[] var3 = testPaths;
        int var4 = testPaths.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String testPath = var3[var5];
            if (matchFiltersURL(testPath, requestPath)) {
                return true;
            }
        }

        return false;
    }
}

执行的时候,按照filterChain中的filter执行

@Component+@WebFilter 配置过滤路径也不起作用

通过@Component将实现类放入到容器中,不添加注解@ServletComponentScan
@Component
@WebFilter(filterName = "myFilter",urlPatterns = "/path")
public class MyFilter implements Filter{}

为什么使用@ServletComponentScan生效 @Component不生效

//WebFilterHandler#doHandle() 解析了@WebFilter注解
public void doHandle(Map<String, Object> attributes, AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterRegistrationBean.class);
        builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
        builder.addPropertyValue("dispatcherTypes", this.extractDispatcherTypes(attributes));
        builder.addPropertyValue("filter", beanDefinition);
        builder.addPropertyValue("initParameters", this.extractInitParameters(attributes));
        String name = this.determineName(attributes, beanDefinition);
        builder.addPropertyValue("name", name);
        builder.addPropertyValue("servletNames", attributes.get("servletNames"));
	//将urlPatterns放入FilterRegistrationBean中
        builder.addPropertyValue("urlPatterns", this.extractUrlPatterns(attributes));
        registry.registerBeanDefinition(name, builder.getBeanDefinition());
    }

//记录了拦截路径

image.png @Component未进行对@WebFilter注解的解析

image.png

添加到FilterMap中的Filter

AbstractFilterRegistrationBean#configure() 如果urlPatterns为空添加的则为“/*”

private static final String[] *DEFAULT_URL_MAPPINGS* = new String[]{"/*"};

if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {
    registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,DEFAULT_URL_MAPPINGS);
} else {
    if (!servletNames.isEmpty()) {
        registration.addMappingForServletNames(dispatcherTypes, this.matchAfter, StringUtils.toStringArray(servletNames));
    }

    if (!this.urlPatterns.isEmpty()) {
        registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, StringUtils.toStringArray(this.urlPatterns));
    }
}

所以通过@Component注入,即使在@WebFilter中配置了url也会拦截所有的请求。

相同的过滤器代码

@WebFilter(urlPatterns = "/user")
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

@ServletComponentScan image.png

@Component

image.png

3.2 过滤器执行顺序问题

ApplicationFilterChain#doFilter()

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
 //省略部分代码
        //执行filter方法
        this.internalDoFilter(request, response);

}

ApplicationFilterChain#internalDoFilter()

private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    if (this.pos < this.n) {
        //根据获取到的filter顺序执行
        ApplicationFilterConfig filterConfig = this.filters[this.pos++];

        try {
            Filter filter = filterConfig.getFilter();
            if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
            }

            if (Globals.IS_SECURITY_ENABLED) {
                Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                Object[] args = new Object[]{request, response, this};
                SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
            } else {
                filter.doFilter(request, response, this);
            }

        } catch (ServletException | RuntimeException | IOException var15) {
            throw var15;
        } catch (Throwable var16) {
            Throwable e = ExceptionUtils.unwrapInvocationTargetException(var16);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.filter"), e);
        }
    } 
    //省略部分代码
}

@Order和@Component 可以保证filter的执行顺序

@Order(1)
@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

@Order(-1)
@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter2 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter2");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

image.png

@Order和@ServletComponentScan 不可以保证顺序

@Order(1)
//@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}


@Order(-1)
//@Component
@WebFilter(urlPatterns = "/user")
public class MyFilter2 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter2");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}


@ServletComponentScan("com.test.filter")
public class Application

按照name排序,@Order注解未起作用

image.png

通过@Configuration配置的filter会按照配置的order顺序执行

    @Bean
    public FilterRegistrationBean myFilter(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.setUrlPatterns(Collections.singleton("/user"));
        filterRegistrationBean.setName("myFilter");
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean myFilter2(){
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter2());
        filterRegistrationBean.setOrder(-1);
        //filterRegistrationBean.setUrlPatterns(Collections.singleton("/user"));
        filterRegistrationBean.setName("myFilter2");
        return filterRegistrationBean;
    }
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}


public class MyFilter2 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("myFilter2");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

image.png