当前位置: 首页 > news >正文

在spring boot工程中使用Filter时,@WebFilter 注解不生效的问题分析和解决方案

1. 问题描述

        首先编写一个Filter类并通过@Component放入spring容器中,通过实现jakarta.servlet中提供的Filter接口完成过滤器的创建,代码如下。

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}@Overridepublic void destroy() {Filter.super.destroy();}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("filter 前置.....");filterChain.doFilter(servletRequest, servletResponse);System.out.println("filter 后置.....");}
}

为了将过滤器配置到目标路径下,通常有两种方法:

        使用servlet提供的@WebFilter注解完成过滤路径的配置。

@Component
@WebFilter(urlPatterns = "/api/*",filterName = "myFilterName") 
public class MyFilter implements Filter {代码同上,省略
}

        使用spring boot推荐的配置类FilterRegistrationBean完成过滤路径的配置。

笔者在使用@WebFilter注解进行过滤路径配置时发现,所有路径下的请求都被过滤了,不受@WebFilter注解中的参数控制,而使用spring推荐的配置类方法则不会出现这个问题。

2. 问题分析

@WebFilter、@WebServlet 和 @WebListener 等与Filter相关的注解均是在Servlet 容器中,spring容器中并没有这些注解,所以即使在Filter类中加上@WebFilter注解并配置好路径参数,spring工程中也读不到这个配置,spring会使用spring配置类的配置,如果spring配置类中没有对Filter进行配置,就会使用默认配置,即针对所以路径进行过滤,所以才会出现以上现象,使用@WebFilter配置类过滤路径,但Filter还是会对所有路径进行过滤。

3. 解决方案

        3.1 spring配置类

        最简单的解决方案就是不使用@WebFilter注解对过滤路径进行配置,而是使用spring推荐的配置类的方式进行配置。

@Configuration  // 专门对 springMVC 底层做一些配置
public class MySpringMVCConfig implements WebMvcConfigurer{@Autowiredprivate MyFilter myFilter;@Beanpublic FilterRegistrationBean getFilter1Registration() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(this.myFilter);//设置过滤器名称和路径,在过滤器类写了的话,这里不用重复写filterRegistrationBean.setName("filter");filterRegistrationBean.addUrlPatterns("/api/*");//设置过滤器执行顺序,数字越小,越早进行过滤,也可设置为负数filterRegistrationBean.setOrder(1);return filterRegistrationBean;}}

3.2 @WebFilter注解      

如果非要使用@WebFilter注解的话:

第一步:需要把@WebFilter添加到容器中,因为spring容器中并没有@WebFilter的注解,这个注解在servlet容器中,故需要在启动类中添加@ServletComponentScan 注解启用 Servlet 容器扫描 @WebFilter@WebServlet@WebListener 注解,将这些组件注册到 Servlet 容器中。

@SpringBootApplication
@ServletComponentScan
public class SpringmvcRestfulCrudApplication {public static void main(String[] args) {SpringApplication.run(SpringmvcRestfulCrudApplication.class, args);}
}

增加此注解后,@WebFilter就成功进入到Serlet容器中,并生效了,能够根据读取@WebFilter中的配置对配置内的路径进行过滤。但如果访问的是@WebFilter配置内的路径,程序会对此路径进行两次过滤,如果访问的路径不在@WebFilter配置内,则依然会被过滤一次。

    这是因为在Filter类中添加了@Component注解,如果同时使用@Component和@ServletComponentScan这两个注解,Filter 类既会被 Spring 容器实例化,也会被 Servlet 容器实例化,导致被实例化两次。spring容器中实例化的Filter依然使用配置类的FilterRegistrationBean配置,如果没有则使用默认配置进行所有路径过滤。

        所以就会出现在启动类增加@ServletComponentScan注解后,如果路径在@WebFilter配置内的访问会被过滤两次,一次是servlet容器实例化的Filter过滤的,另一次是spring容器实例化的Filter过滤。如果路径不在@WebFilter配置内依然会被过滤一次,这一次是spring容器中的Filter使用了默认配置进行的全路径过滤。

第二步:为了使用@WebFilter进行配置,不受spring容器实例化的Filter干扰,即将Filter类中的@Component注解删掉,Filter类不受spring容器控制,也不会进行实例化,这样就不会有两个实例化的Filter进行相互干扰了。

//@Component 不放到spring容器中管理
@WebFilter(urlPatterns = "/api/*",filterName = "myFilterName") 
public class MyFilter implements Filter {代码同上,省略
}

4 总结

        综上所述,如果在spring boot工程中使用过滤器Filter,推荐在配置类中使用FilterRegistrationBean进行过滤路径配置,并在Filter类中添加@Component将Filter类加载到spring容器中。

        如果要使用@WebFilter进行过滤路径的配置,则需要在启动类中添加@ServletComponentScan注解启用Servlet容器扫描@WebFilter注解,并删除Filter类中的@Component注解,防止spring实例化的Filter与Servlet容器实例化的Filter冲突。

今后读者在使用过程中只要意识到自己过滤器Filter是由spring实例化的还是servlet实例化的,两个实例化的Filter所使用的配置方式不一样,要使用对应的配置方式。万万不可同时使用@Component注解和@ServletComponetScan注解。

http://www.lryc.cn/news/484877.html

相关文章:

  • 浅谈“通感一体”
  • 【Linux】监控系统Zabbix的安装与配置
  • Springboot定时任务
  • node.js知识点总结
  • Kotlin中泛型的协变
  • 第三百二十五节 Java线程教程 - Java Fork/Join框架
  • 网络游戏安全现状及相关应对方案
  • uniapp h5地址前端重定向跳转
  • uniapp隐藏自带的tabBar
  • 使用--log-file保存pytest的运行日志
  • WebAPI性能监控-MiniProfiler与Swagger集成
  • 视频会议接入GB28181视频指挥调度,语音对讲方案
  • 深度学习和图像处理
  • 〔 MySQL 〕数据类型
  • 云安全之云计算基础
  • PostgreSQL pg-xact(clog)目录文件缺失处理
  • 《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
  • 基于碎纸片的拼接复原算法及MATLAB实现
  • 苍穹外卖 软件开发流程
  • mysqldump导出表结构和表数据和存储过程和函数
  • 常见的排序算法及分类对比
  • 多窗口切换——selenium
  • LFD STM32编程规范20241111
  • Python学习------第八天
  • 【扩散——BFS】
  • C++ 编程基础(5)类与对象 | 5.5、多态
  • 客户端发送http请求进行流量控制
  • STM32 低功耗模式详解
  • 我的第一个PyQt5程序
  • Unity调用Python