千家信息网

SpringBoot web中过滤器Filter的使用方法

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章给大家介绍SpringBoot web中过滤器Filter的使用方法,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。这里介绍另外一种直接将 Filter 当做 Spring
千家信息网最后更新 2026年11月03日SpringBoot web中过滤器Filter的使用方法

这篇文章给大家介绍SpringBoot web中过滤器Filter的使用方法,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

这里介绍另外一种直接将 Filter 当做 Spring 的 Bean 来使用的方式,并且在这种使用方式下,Filter 的优先级可以直接通过@Order注解来指定;最后将从源码的角度分析一下两种不同的使用方式下,为什么@Order注解一个生效,一个不生效

I. Filter

本篇博文的工程执行的环境依然是SpringBoot2+, 项目源码可以在文章最后面 get

1. 使用姿势

前面一篇博文,介绍了两种使用姿势,下面简单介绍一下

WebFilter 注解

在 Filter 类上添加注解@WebFilter;然后再项目中,显示声明@ServletComponentScan,开启 Servlet 的组件扫描

@WebFilterpublic class SelfFilter implements Filter {}@ServletComponentScanpublic class SelfAutoConf {}

FilterRegistrationBean

另外一种方式则是直接创建一个 Filter 的注册 Bean,内部持有 Filter 的实例;在 SpringBoot 中,初始化的是 Filter 的包装 Bean 就是这个

@Beanpublic FilterRegistrationBean orderFilter() {    FilterRegistrationBean filter = new FilterRegistrationBean<>();    filter.setName("orderFilter");    filter.setFilter(new SelfFilter());    filter.setOrder(-1);    return filter;}

本篇将介绍另外一种方式,直接将 Filter 当做普通的 Bean 对象来使用,也就是说,我们直接在 Filter 类上添加注解@Component即可,然后 Spring 会将实现 Filter 接口的 Bean 当做过滤器来注册

而且这种使用姿势下,Filter 的优先级可以通过@Order注解来指定;

设计一个 case,定义两个 Filter(ReqFilter和OrderFilter), 当不指定优先级时,根据名字来,OrderFilter 优先级会更高;我们主动设置下,希望ReqFilter优先级更高

@Order(1)@Componentpublic class ReqFilter 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("req filter");        chain.doFilter(request, response);    }    @Override    public void destroy() {    }}@Order(10)@Componentpublic class OrderFilter 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("order filter!");        chain.doFilter(request, response);    }    @Override    public void destroy() {    }}

2. 优先级测试

上面两个 Filter 直接当做了 Bean 来写入,我们写一个简单的 rest 服务来测试一下

@RestControllerpublic class IndexRest {    @GetMapping(path = {"/", "index"})    public String hello(String name) {        return "hello " + name;    }}@SpringBootApplicationpublic class Application {    public static void main(String[] args) {        SpringApplication.run(Application.class);    }}

请求之后输出结果如下, ReqFilter 优先执行了

II. 源码分析

当我们直接将 Filter 当做 Spring Bean 来使用时,@Order注解来指定 Filter 的优先级没有问题;但是前面一篇博文中演示的@WebFilter注解的方式,则并不会生效

  • 这两种方式的区别是什么?

  • @Order注解到底有什么用,该怎么用

1. Bean 方式

首先我们分析一下将 Filter 当做 Spring bean 的使用方式,我们的目标放在 Filter 的注册逻辑上

第一步将目标放在: org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize

下面的逻辑中包括了 ServeltContext 的初始化,而我们的 Filter 则可以看成是属于 Servlet 的 Bean

private void selfInitialize(ServletContext servletContext) throws ServletException {        prepareWebApplicationContext(servletContext);        ConfigurableListableBeanFactory beanFactory = getBeanFactory();        ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(                        beanFactory);        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,                        getServletContext());        existingScopes.restore();        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,                        getServletContext());        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {                beans.onStartup(servletContext);        }}

注意上面代码中的 for 循环,在执行getServletContextInitializerBeans()的时候,Filter 就已经注册完毕,所以我们需要再深入进去

将目标集中在org.springframework.boot.web.servlet.ServletContextInitializerBeans#ServletContextInitializerBeans

public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {        this.initializers = new LinkedMultiValueMap<>();        addServletContextInitializerBeans(beanFactory);        addAdaptableBeans(beanFactory);        List sortedInitializers = this.initializers.values()                        .stream()                        .flatMap((value) -> value.stream()                                        .sorted(AnnotationAwareOrderComparator.INSTANCE))                        .collect(Collectors.toList());        this.sortedList = Collections.unmodifiableList(sortedInitializers);}

上面有两行代码比较突出,下面单独捞出来了,需要我们重点关注

addServletContextInitializerBeans(beanFactory);addAdaptableBeans(beanFactory);

通过断点进来,发现第一个方法只是注册了dispatcherServletRegistration;接下来重点看第二个

@SuppressWarnings("unchecked")private void addAdaptableBeans(ListableBeanFactory beanFactory) {        MultipartConfigElement multipartConfig = getMultipartConfig(beanFactory);        addAsRegistrationBean(beanFactory, Servlet.class,                        new ServletRegistrationBeanAdapter(multipartConfig));        addAsRegistrationBean(beanFactory, Filter.class,                        new FilterRegistrationBeanAdapter());        for (Class listenerType : ServletListenerRegistrationBean                        .getSupportedTypes()) {                addAsRegistrationBean(beanFactory, EventListener.class,                                (Class) listenerType,                                new ServletListenerRegistrationBeanAdapter());        }}

从上面调用的方法命名就可以看出,我们的 Filter 注册就在addAsRegistrationBean(beanFactory, Filter.class, new FilterRegistrationBeanAdapter());

上面的截图就比较核心了,在创建FilterRegistrationBean的时候,根据 Filter 的顺序来指定最终的优先级

然后再回到构造方法中,根据 order 进行排序, 最终确定 Filter 的优先级

2. WebFilter 方式

接下来我们看一下 WebFilter 方式为什么不生效,在根据我的项目源码进行测试的时候,请将需要修改一下自定义的 Filter,将类上的@WebFilter注解打开,@Component注解删除,并且打开 Application 类上的ServletComponentScan

我们这里 debug 的路径和上面的差别不大,重点关注下面ServletContextInitializerBeans的构造方法上面

当我们深入addServletContextInitializerBeans(beanFactory);这一行进去 debug 的时候,会发现我们自定义的 Filter 是在这里面完成初始化的;而前面的使用方式,则是在addAdapterBeans()方法中初始化的,如下图

在getOrderedBeansOfType(beanFactory, ServletContextInitializer.class)的调用中就返回了我们自定义的 Bean,也就是说我们自定义的 Filter 被认为是ServletContextInitializer的类型了

然后我们换个目标,看一下 ReqFilter 在注册的时候是怎样的

关键代码: org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

(因为 bean 很多,所以我们可以加上条件断点)

通过断点调试,可以知道我们的自定义 Filter 是通过WebFilterHandler类扫描注册的, 对这一块管兴趣的可以深入看一下org.springframework.boot.web.servlet.ServletComponentRegisteringPostProcessor#scanPackage

上面只是声明了 Bean 的注册信息,但是还没有具体的实例化,接下来我们回到前面的进程,看一下 Filter 的实例过程

private  List> getOrderedBeansOfType(                        ListableBeanFactory beanFactory, Class type, Set excludes) {                Comparator> comparator = (o1,                                o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getValue(),                                                o2.getValue());                String[] names = beanFactory.getBeanNamesForType(type, true, false);                Map map = new LinkedHashMap<>();                for (String name : names) {                        if (!excludes.contains(name) && !ScopedProxyUtils.isScopedTarget(name)) {                                T bean = beanFactory.getBean(name, type);                                if (!excludes.contains(bean)) {                                        map.put(name, bean);                                }                        }                }                List> beans = new ArrayList<>();                beans.addAll(map.entrySet());                beans.sort(comparator);                return beans;        }

注意我们的 Filter 实例在T bean = beanFactory.getBean(name, type);

通过这种方式获取的 Filter 实例,并不会将 ReqFilter 类上的 Order 注解的值,来更新FilterRegistrationBean的 order 属性,所以这个注解不会生效

最后我们再看一下,通过 WebFilter 的方式,容器类不会存在ReqFilter.class类型的 Bean, 这个与前面的方式不同

III. 小结

主要介绍了另外一种 Filter 的使用姿势,将 Filter 当做普通的 Spring Bean 对象进行注册,这种场景下,可以直接使用@Order注解来指定 Filter 的优先级

但是,这种方式下,我们的 Filter 的很多基本属性不太好设置,一个方案是参考 SpringBoot 提供的一些 Fitler 的写法,在 Filter 内部来实现相关逻辑

关于SpringBoot web中过滤器Filter的使用方法就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

方式 注解 优先级 方法 实例 时候 姿势 源码 目标 过滤器 接下来 代码 断点 来使 逻辑 重点 面的 项目 分析 测试 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 关于新基建和互联网科技 互联网科技视频 电子科技大学互联网 奔汉互联网科技 互联网养老 桔豆科技 富国互联网科技创新基金 汽车互联网创新科技园 互联网科技与大数据专业 消费医药和互联网科技 呼和浩特新华互联网科技学院 互联网科技创新的路径 广东工业互联网大赛深圳学泰科技 云南省自由互联网科技有限公司 吉林省码上互联网科技电话 互联网时代科技型公司的机会 互联网科技机房 北京天晋互联网科技有限公司 互联网领先科技成果宣传视频 银川新华互联网科技学校招聘 如何强化互联网金融科技 没上市的科技互联网公司 科技服务与互联网 互联网科技公司有哪些 上海卓越科技 互联网 恒银科技与互联网金融 重庆互联网医院沙龙医盟信息科技 广州市恰铎互联网科技有限公司 互联网科技如何创业 上海钢联属于互联网科技股吗 萌小萌互联网科技河南有限公司
0