ListenerFilterServlet是Java Web开发过程中常用的三个组件,其中Filter组件的使用频率最高,经常被用来做简单的权限处理、请求头过滤和防止XSS攻击等。如果我们使用的是传统的Spring MVC进行开发,那么只需要在Tomcat的web.xml文件中进行如下配置即可:

<!-- 配置Listener -->
<listener>
    <listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> 

<!--配置Filter,这边配置了一个Filter,但是匹配了多个url-pattern-->
<!-- 以url-partern方式配置的filter中,如果有多个与当前请求匹配,则按web.xml中filter-mapping出现的顺序来运行-->
<filter>
    <filter-name>filter1</filter-name>
    <filter-class>com.csx.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/url/a/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>filter1</filter-name>
    <url-pattern>/url/b/*</url-pattern>
</filter-mapping>

<!--配置Servlet-->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.spring.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!-- 这边不建议写成/* -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

PS:在容器启动的时候,上面三个组件启动的顺序是Listener --> Filter --> Servlet,这边安利一个记忆的方法:把启动顺序记忆成“理(Listener)发(Filter)师(Servlet)”即可。

在web.xml中配置这三个组件比较简单,但是使用Spring-Boot开发时使用的是嵌入式容器,并没有web.xml文件让我们进行配置。那么在Spring-Boot中到底要怎么配置ListenerFilterServlet等组件呢?

本篇博客以Filter为列,介绍下在Spring-Boot中怎么配置ListenerFilterServlet等组件。

方式一:将Filter声明为bean

这边我们先来自定义一个Filter,这个Filter的作用是统计一个接口的调用时间。

public class TimeConsumingCalculationFilter implements Filter {

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            HttpServletRequest httpRequest=(HttpServletRequest)request;
            long startTime = System.nanoTime();
            logger.info(">>>>>>> Begin ["+httpRequest.getRequestURI()+"]...");
            try{
                chain.doFilter(request, response);
            }finally {
                long endTime = System.nanoTime();
                logger.info(">>>>>>> End ["+httpRequest.getRequestURI()+"]["+(endTime-startTime)/1000/1000.0+"ms].");
            }
        }

    }

在Spring-Boot中配置上面的Filter,我们只需要在@Configuration文件中做如下配置即可:

@Configuration
public class WebConfig {

    private static Logger logger = LoggerFactory.getLogger(WebConfig.class);

    @Bean
    public Filter filter1(){
        return new TimeConsumingCalculationFilter();
    }
}

上面的Filter默认会拦截所有请求。假如我们想要配置多个拦截器的话,只要再加一个Bean方法就可以了。

@Configuration
public class WebConfig {

    private static Logger logger = LoggerFactory.getLogger(WebConfig.class);

    @Bean
    public Filter filter1(){
        return new TimeConsumingCalculationFilter();
    }

    @Bean
    public Filter filter2() {
        return new TimeConsumingCalculationFilter2();
    }
}

上面的配置代码配置了两个Filter,两个Filter默认都会拦截所有请求,拦截的顺序是:filter1-->filter2。这边的逻辑是先配置的Filter先拦截,后配置的Filter后拦截。当然,如果我们想明确指定拦截顺序的话可以借助@Order注解。但是需要注意的是这个注解一定要加在定义的类上面。

@Order(Ordered.LOWEST_PRECEDENCE - 2)
public class TimeConsumingCalculationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       //your logic
    }

}
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class TimeConsumingCalculationFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       //your logic
    }

}

PS: @Order中的value值越大,执行的优先级越小。值越小,优先级越大。当我们自定义执行顺序的时候,建议使用@Order(Ordered.LOWEST_PRECEDENCE - 1)这种形式配置,Ordered.LOWEST_PRECEDENCE减去的值越大,优先级越高,这样看起来比较直观。

另外,Spring还提供了一个OrderedFilter接口,这个接口是FilterOrdered的组合接口,原理和上面的是一样的。大家可以看情况使用。

上面的这种配置方式优点是配置起来非常简单,但是缺点也比较明显,就是配置不够灵活,默认会拦截所有请求。

方式二:@WebFilter方式

@WebFilter注解是Servlet中提供的注解,Spring也支持这个注解。@WebFilter能进行细粒度的进行配置,比上面的方式更加灵活。

@Configuration
public class WebConfig {
    //可以自定义url-pattern
    @WebFilter(urlPatterns="/*")
    @Order(Ordered.LOWEST_PRECEDENCE - 2)
    //这边如果不加`@Configuration`,需要通过`@ServletComponentScan`扫描`Listener`、`Filter`和`Servlet`这三个组件
    @Configuration
    public class TimeConsumingCalculationFilter implements Filter {

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            //your logic
        }
    }   

    @WebFilter(urlPatterns="/*")
    @Order(Ordered.LOWEST_PRECEDENCE - 2)
    //这边如果不加`@Configuration`,需要通过`@ServletComponentScan`扫描`Listener`、`Filter`和`Servlet`这三个组件
    @Configuration
    public class TimeConsumingCalculationFilter2 implements Filter {

        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            //your logic
        }
    }   

}

通过 @WebFilter 注解的方式配置Filter简单,而且能够自定义url-pattern和拦截顺序。

方式三:使用FilterRegistrationBean配置

@Configuration
public class WebConfig {

    private static Logger logger = LoggerFactory.getLogger(WebConfig.class);

    @Bean
        public FilterRegistrationBean<Filter> filter1() {
            FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
            registrationBean.setName("filter1");
            registrationBean.setOrder(Ordered.LOWEST_PRECEDENCE - 2);
            registrationBean.setFilter(new TimeConsumingCalculationFilter());
            registrationBean.addUrlPatterns("/foo/*");
            return registrationBean;
        }

        @Bean
        public FilterRegistrationBean<Filter> filter2() {
            FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
            registrationBean.setName("filter2");
            registrationBean.setOrder(Ordered.LOWEST_PRECEDENCE - 3);
            registrationBean.setFilter(new TimeConsumingCalculationFilter1());
            registrationBean.addUrlPatterns("/*");
            registrationBean.addInitParameter("key1","value1");
            registrationBean.addInitParameter("key2","value2");
            //通过Servlet name匹配Filter,不建议使用
            registrationBean.addServletNames("name1");
            return registrationBean;
        }

}

注意点:

  • FilterRegistrationBean 与 Filter 之间是一对一关系。
  • 如果存在多个 FilterRegistrationBean 需要调用其 setName(String name) 为其声明唯一名称,否则只有第一个注册成功的有效。
  • 如果需要保证调用顺序可通过调用其 setOrder(int order) 方法进行设置。

方式四:使用DelegatingFilterProxyRegistrationBean方式

@Configuration
public class WebConfig {

    @Bean("myFilter")
    //配置了DelegatingFilterProxyRegistrationBean后,这种方式配置的Filter不会生效了,只会拦截/foo/*的请求
    public Filter myFilter(){
        return new TimeConsumingCalculationFilter();
    }

    @Bean
    public DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean(){
        DelegatingFilterProxyRegistrationBean filterProxy = new DelegatingFilterProxyRegistrationBean("myFilter");
        filterProxy.addUrlPatterns("/foo/*");
        filterProxy.addInitParameter("targetFilterLifecycle","true");
        filterProxy.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico");
        filterProxy.setDispatcherTypes(DispatcherType.REQUEST);
        return filterProxy;
    }

}

FilterRegistrationBean和DelegatingFilterProxyRegistrationBean区别:

  • FilterRegistrationBean通过onStartup方法直接注册filter。
  • DelegatingFilterProxyRegistrationBean是将DelegatingFilterProxy注册到Servlet3.0+的容器中,同时实现了ApplicationContextAware接口,实例ApplicationContext通过通过传入自定义filter的名称查找对应的bean,并生成相应bean的代理对象。

触类旁通

  • 添加自定义Servlet 也可采用方法一@WebServlet 或者ServletRegistrationBean
  • 添加自定义Listener也可以采用方法一 @WebListener或者ServletListenerRegistrationBean ,注意监听事件是泛型

其他相关类

  • ServletComponentRegisteringPostProcessor
  • ServletComponentHandler
  • WebListenerHandler
  • WebFilterHandler
  • WebServletHandler

参考

  • https://blog.csdn.net/loveForever_xiang/article/details/101270633
  • https://www.liangzl.com/get-article-detail-121998.html
  • https://mp.weixin.qq.com/s/t8WdKEkYJuRApeEEOvXR_A
  • https://blog.csdn.net/andy_zhang2007/article/details/90399870

Spring-Boot使用嵌入式容器,那怎么配置自定义Filter呢的更多相关文章

  1. Spring Boot 系列(三)属性配置&自定义属性配置

    在使用spring boot过程中,可以发现项目中只需要极少的配置就能完成相应的功能,这归功于spring boot中的模块化配置,在pom.xml中依赖的每个Starter都有默认配置,而这些默认配 ...

  2. Spring Boot 容器选择 Undertow 而不是 Tomcat Spring Boot 内嵌容器Unde

    Spring Boot 内嵌容器Undertow参数设置 配置项: # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 不要设置过大,如果过大,启动 ...

  3. Spring Boot中只能有一个WebMvcConfigurationSupport配置类

    首先将结论写文章的最前面,一个项目中只能有一个继承WebMvcConfigurationSupport的@Configuration类(使用@EnableMvc效果相同),如果存在多个这样的类,只有一 ...

  4. 分布式事务、多数据源、分库分表中间件之spring boot基于Atomikos+XADataSource分布式事务配置(100%纯动态)

    本文描述spring boot基于Atomikos+DruidXADataSource分布式事务配置(100%纯动态),也就是增加.减少数据源只需要修改application.properties文件 ...

  5. Spring Boot 多模块项目创建与配置 (一) (转)

    Spring Boot 多模块项目创建与配置 (一) 最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多个模块.代码中的多模块是用maven管理的,每个模块都 ...

  6. Spring Boot 源码分析 数据源 + Mybatis 配置

    公司今年开始使用 Spring Boot 开发,当然使用 Spring Boot 也是大势所趋,尤其是现在微服务的趋向,当然是选择基于Spring Boot 的 Spring Cloud.(所谓的 S ...

  7. Spring Boot 多模块项目创建与配置 (一)

    最近在负责的是一个比较复杂项目,模块很多,代码中的二级模块就有9个,部分二级模块下面还分了多个模块.代码中的多模块是用maven管理的,每个模块都使用spring boot框架.之前有零零散散学过一些 ...

  8. Spring Boot 2.x Redis多数据源配置(jedis,lettuce)

    Spring Boot 2.x Redis多数据源配置(jedis,lettuce) 96 不敢预言的预言家 0.1 2018.11.13 14:22* 字数 65 阅读 727评论 0喜欢 2 多数 ...

  9. 51. spring boot属性文件之多环境配置【从零开始学Spring Boot】

    原本这个章节是要介绍<log4j多环境不同日志级别的控制的>但是没有这篇文章做基础的话,学习起来还是有点难度的,所以我们先一起了解下spring boot属性文件之多环境配置,当然文章中也 ...

  10. Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现

    Spring Boot 内嵌容器 Tomcat / Undertow / Jetty 优雅停机实现 Anoyi 精讲JAVA 精讲JAVA 微信号 toooooooozi 功能介绍 讲解java深层次 ...

随机推荐

  1. 洛谷P3957 跳房子 题解 二分答案/DP/RMQ

    题目链接:https://www.luogu.org/problem/P3957 这道题目我用到了如下算法: 线段树求区间最大值: 二分答案: DP求每一次枚举答案g时是否能够找到 \(\ge k\) ...

  2. MATLAB常用函数, 常见问题

    MATLAB常用函数 1.常用取整函数 round(x):四舍五入函数 floor(x) : 向下取整, 即 floor(1.2)=1,  floor(1.8) = 1 ceil(x) : 向上取整, ...

  3. Python数据可视化matplotlib和seaborn

    Python在数据科学中的地位,不仅仅是因为numpy, scipy, pandas, scikit-learn这些高效易用.接口统一的科学计算包,其强大的数据可视化工具也是重要组成部分.在Pytho ...

  4. IntStack(存放int型值,带迭代器) 附模板化实现 p406

    1 该栈只用于存在int型数据 #include "../require.h" #include <iostream> using namespace std; cla ...

  5. [转]Jquery属性选择器(同时匹配多个条件,与或非)(附样例)

    1. 前言 为了处理除了两项不符合条件外的选择,需要用到jquery选择器的多个条件匹配来处理,然后整理了一下相关的与或非的条件及其组合. 作为笔记记录. 2. 代码 1 2 3 4 5 6 7 8 ...

  6. 学习vue就是那么简单,一个简单的案例

    vue是前端兴起的一个javascript库,相信大家都使用过jQuery,虽然vue和jQuery没有可比性,但从熟悉的角度去理解新的东西或许会容易接受一些,有时候由于思想和模式的转变会带来阵痛,但 ...

  7. asp dotnet core 图片在浏览器没访问可能原因

    我写了一个项目用来广告就用到广告的图片,但是广告的图片放在博客的链接无法访问,连我的方法都没有调用,而我尝试网页直接访问图片链接是可以访问的,最后找到原因是广告插件禁用了图片访问 我在一个方法创建了广 ...

  8. 【codeforces 749A】Bachgold Problem

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  9. WPF 一个性能比较好的 gif 解析库

    本文介绍 Magick.NET ,这是 ImageMagick 的 .Net 封装,他支持 100 多种格式的图片,而 gif 也是他支持的.本文告诉大家如何使用这个库播放 gif 图 先给大家看一下 ...

  10. 一个vue管理系统的初步搭建总结

    ps:目前这个项目只是有一个大致的框架,并没有做完 前期准备工作 前端构建工具:Visual Studio Code后端构建工具:IDEA数据库和服务器构建工具:WampServer (使用的是2.4 ...