过滤器的4种创建方式

1.实现Filter接口,添加@Component成为bean

java 复制代码
@Component
public class MyFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(MyFilter.class);

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("1.实现Filter接口,添加@Component成为bean");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String uri = request.getRequestURI();
        if (uri.startsWith("/user/")) {
            log.info("execute plan A");
        } else if (uri.startsWith("/goods/")) {
            log.info("execute plan B");
        } else {
            log.info("execute plan C");
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

这里的 Filter 的全路径是:jakarta.servlet.Filter。

这种创建过滤器的方式默认会拦截所有接口,需要在 doFilter 方法中手动添加处理逻辑。

因为这里的过滤器是一个 bean,可以用 @Order 注解或者实现 Ordered 接口设置优先级。

Ordered 接口 > @Order 注解。

java 复制代码
public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}

Filter 里面有三个方法,init 和 destroy 是默认方法,可以不重写。

如果需要在这个过滤器的生命周期做事情的话再重写。

2.实现Filter接口,通过FilterRegistrationBean注册成为bean

依旧让一个类实现 Filter 接口,但是不需要添加 @Component 注解。

java 复制代码
public class MyFilter implements Filter {
    private static final Logger log = LoggerFactory.getLogger(MyFilter.class);

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("2.实现Filter接口,通过FilterRegistrationBean注册成为bean");
        log.info("do something");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
java 复制代码
@Configuration
public class FilterConfig {
    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistrationBean() {
        FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new MyFilter());
        bean.setOrder(1);
        bean.addUrlPatterns("/*");
        return bean;
    }
}

在配置类中返回 FilterRegistrationBean 对象作为 bean。

在配置类中可以设置拦截规则、优先级。

但是有个问题,这里的 MyFilter 是我们自己手动创建的,new MyFilter() 嘛,所以这个对象不会被 Spring 管理,在 MyFilter 中无法自动注入其他 bean,会抛 NullPointerException。

如果需要在 MyFilter 中注入 bean,就要让 MyFilter 被 Spring 管理,也就是给 MyFilter 添加 @Component 注解。

java 复制代码
@Configuration
public class FilterConfig {
    @Autowired
    private MyFilter myFilter;

    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistrationBean() {
        FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(myFilter);
        bean.setOrder(1);
        bean.addUrlPatterns("/*");
        return bean;
    }
}

3.实现Filter接口,添加@WebFilter,启动类添加@ServletComponentScan

java 复制代码
@WebFilter(urlPatterns = "/*", filterName = "myFilter")
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("3.实现Filter接口,添加@WebFilter,启动类添加@ServletComponentScan");
        log.info("do something");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

MyFilter 要实现 Filter 接口,然后添加 @WebFilter 注解。

java 复制代码
@SpringBootApplication
@ServletComponentScan
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

启动类要添加 @ServletComponentScan 注解,否则 MyFilter 不会生效。

第三种方式比较特殊:

  • MyFilter 中可以注入 bean。
  • 但是无法通过 @Order 注解和 Ordered 接口指定优先级,而是按照类名排序,类名就是字符串嘛,所以是根据字符串排序。(不是 filterName,是类名)

4.继承OncePerRequestFilter,添加@Component成为bean

java 复制代码
@Component
public class MyFilter extends OncePerRequestFilter {
    private static final Logger log = LoggerFactory.getLogger(MyFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        log.info("4.继承OncePerRequestFilter,添加@Component成为bean");
        filterChain.doFilter(request, response);
    }
}

OncePerRequestFilter 是 Spring 提供的过滤器,保证一次请求只执行一次。

跟第一种方式一样,可以注入 bean,可以设置优先级。

也可以像第二种方式一样,在配置类中注册到 FilterRegistrationBean 中。

java 复制代码
@Configuration
public class FilterConfig {
    @Autowired
    private MyFilter myFilter;

    @Bean
    public FilterRegistrationBean<MyFilter> myFilterRegistrationBean() {
        FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(myFilter);
        bean.setOrder(1);
        bean.addUrlPatterns("/api/*");
        return bean;
    }
}
相关推荐
SL_staff1 小时前
制造业交付崩盘?用跨部门节点协同计划打通销售、生产与质量链路
java·开源·产品
文丑颜不良啊2 小时前
LeetCode2261~2280题目解析
java·leetcode
SL_staff2 小时前
告别规则黑盒:JVS-Rules 在金融风控中的可视化决策编排实践
java·产品·全栈
逃逸线LOF2 小时前
服务网关Gateway
java·运维·gateway
灿飞屋3 小时前
Kotlin与Java虚拟机四:函数
java·python·kotlin·安卓·android jetpack
阡陌数智4 小时前
Claude API新版本重大变更与安全升级指南
java·linux·安全
学长毕设5 小时前
基于SpringBoot的野生动物公益保护平台设计与实现-附源码
java·spring boot·后端
SL_staff6 小时前
离散制造排程破局:JVS-APS 四步闭环落地实践(开发者视角)
java·产品·全栈
这个昵称不容易6 小时前
SpringBoot 美容院管理系统:232个Java文件315个接口,5套角色从预约到发货一整条链路
java·springboot·毕设
装不满的克莱因瓶7 小时前
【SpringAI Alibaba】ReactAgent记忆管理MessageTrimmingHook与MessageDeletionHook
java·人工智能·ai·ai编程·springai·springaialibaba