The Springboot project quickly implements the filter function

foreword

Many times, when you think you have grasped the truth, if you can go a little deeper, you may discover some other truths. For example, the best programming practice for aspect-oriented programming is AOP. The main function of AOP is to define the entry point and weave some additional unified operations vertically at the entry point to avoid excessive coupling with business code. Anyone who is familiar with java web projects knows that there are also filters and interceptors that have AOP-like features, so the question arises: Why does aspect-oriented programming generally refer to AOP, not filters and interceptors? device? How are filters and interceptors implemented in Spring boot? What is the difference between these three? The related implementation of AOP is shared in the Springboot project’s rapid implementation of Aop functions. Next, we will use two to three articles to share with you the implementation of filters and interceptors, as well as the horizontal comparison between AOP, filters and interceptors . , so that in business development, the specific implementation method can be quickly and correctly selected.

Environment configuration

jdk version: 1.8

Development tools: Intellij iDEA 2020.1

springboot:2.3.9.RELEASE

Introduction to Filter

Filter, Chinese means filter, the fully qualified class name of Filter is javax.servlet.Filter, it can be seen that this is an interface related to servlet; the core of SpringMVC is DispatcherServlet, and DispatcherServlet inherits Servlet, and then it can be inferred that Filter It is also associated with SpringMVC.

In fact, this speculation is also correct. In the SpringMVC project, the filter acts as a filter between the browser and the server. It can intercept the request and response information between the client and the server, and make decisions based on these request-response information. Some other operations, but note that filter cannot change the request-response information;

core class

Filter

The fully qualified class name of the Filter interface is javax.servlet.Filter, which has three methods, namely

1. init(...): used to initialize Filter;

2. doFilter(...): The specific implementation of filtering requests and intercepting response information is in this method;

3. destroy(...): Triggered when the Filter object is destroyed, mainly used to do some finishing work, such as the release of resources;

FilterConfig

The fully qualified class name of the FilterConfig interface is javax.servlet.FilterConfig, which has four main methods, namely:

1. getFilterName() Get the name of the Filter;

2. getServletContext() Gets the ServletContext object (ie application);

3. getInitParameter() Get the initialization parameters of Filter;

4. getInitParameterNames() Get the names of all initialization parameters;

FilterChain

The fully qualified class name of the FilterChainr interface is javax.servlet.FilterChain. This interface has only one method, which is the doFilter() method, which is used to call the next filter on the Filter chain. If the current filter is the last or only one filter , the filter sends the request to the target resource.

MyFilter2 is a self-implemented filter that implements the Filter interface; the Filter interface relies on the FilterChain interface and the FilterConfig interface, where the implementation class of the FilterChain interface is org.apache.catalina.core.ApplicationFilterChain, and the implementation class of the FilterConfig interface is org.apache.catalina .core.ApplicationFilterConfig;

working principle

1. When the project starts, execute the construction method of Filter first, and complete the registration of related Filter objects;

2. Immediately afterwards, the init() method of the Filter object is called, and some initialization operations are started on the Filter;

3、项目启动完成后,客户端每次向服务端发起请求时,如果请求地址与过滤器定义的地址匹配,则会执行Filter的doFilter();如果匹配上多个过滤器,则会形成一个链路,依次调用各个过滤器对象的doFilter();服务端作出响应后,也会再次执行到各个过滤器对象的doFilter();请求和响应时,过滤器链的执行顺序是先进后出;

4、服务器停止时调用Filter的destroy()方法,用来释放资源。

实现方式

Springboot项目中一般有两种方式:

1、@WebFilter注解,即javax.servlet.annotation.WebFilter;

2、FilterRegistrationBean,即org.springframework.boot.web.servlet.FilterRegistrationBean;

两种方式,都需要在启动类上增加注解@ServletComponentScan,用于开启servlet相关bean的扫描,其中包含有过滤器(Filter);

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

代码实现

1、WebFilter注解里,定义一下过滤器的名字,以及要对哪些请求进行过滤,“/*”表示对所有的请求都过滤,在实际业务中,可具体对待;如果在初始化的时候,需要携带一些初始化的参数,可以在initParams属性上,使用@WebInitParam注解来定义初始化参数名称和具体的值,这些参数可以在filter对象初始化的时候获取到;MyFIlter1和MyFIlter2使用的注解方式定义的过滤器;

@Slf4j
@WebFilter(filterName = "myFilter1", urlPatterns = "/*", initParams = {@WebInitParam(name = "creator", value = "fanfu")})
public class MyFilter1 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("//myFilter1初始化开始");
        String creator = filterConfig.getInitParameter("creator");
        log.info("//初始化参数creator:{}",creator);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//myFilter1开始执行");
        chain.doFilter(request, response);
        log.info("//myFilter1结束执行");
    }

    @Override
    public void destroy() {
        log.info("//myfilter1被销毁");
    }
}
@Slf4j
@WebFilter(filterName = "myFilter2", urlPatterns = "/*")
public class MyFilter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("//myFilter2初始化开始");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//myFilter2开始执行");
        chain.doFilter(request, response);
        log.info("//myFilter2结束执行");
    }

    @Override
    public void destroy() {
        log.info("//myFilter2被销毁");
    }
}

2、FilterRegistrationBean方式

在Springboot项目的配置类中,使用FilterRegistrationBean来包装自定义的过滤器,这种方式的最大好处就是可以自定义过滤器的执行顺序,数字越小,执行时的优先级就越高;MyFIlter3和MyFIlter4是使用FilterRegistrationBean方式定义的过滤器;

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean filterRegistration1() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter3());
        filterRegistrationBean.addUrlPatterns("/*");//定义过滤器对哪些请求路径进行过滤,/*表示对所有请求都过滤
        filterRegistrationBean.setOrder(2);//定义过滤器的执行优先级,数据越小优先级越高
        return filterRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistration2() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter4());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }
}
@Slf4j
public class MyFilter3 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    log.info("//MyFilter3初始化开始");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//MyFilter3开始执行");
        chain.doFilter(request,response);
        log.info("//MyFilter3结束执行");
    }

    @Override
    public void destroy() {
        log.info("//MyFilter3被销毁");
    }
}
@Slf4j
public class MyFilter4 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("//MyFilter4初始化开始");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("//MyFilter4开始执行");
        chain.doFilter(request,response);
        log.info("//MyFilter4结束执行");
    }

    @Override
    public void destroy() {
        log.info("//MyFilter4被销毁");
    }
}

未定义myFilter3、myFilter4的执行优先级,即采取自然排序时的执行结果:在请求前myFilter3的执行时机早于myFilter4,响应后myFilter3的执行时机要晚于myFilter4;

定义myFilter4的优先级高于myFilter3时,执行结果:在请求前myFilter4的执行时机早于myFilter3,响应后的myFilter4的执行时机要晚于myFilter3;

总结

过滤器的实现是比较简单,通过梳理这个过程,我get到以下几个点:

1、过滤器是用于SpringMVC项目中,即与servlet相关的项目;

2、过滤器的执行时机是在请求前和响应后,有两种实现方式,即@WebFilter注解和FilterRegistrationBean;如果对过滤器的执行顺序没有限制要求,则可以使用第一种;如果对过滤器的执行顺序有明确限制,则可以使用第二种;

3、如果有多个过滤器对象时,会形成一个过滤器链,过滤器的执行顺序是先进后出;

4、过滤器可以过滤请求和拦截响应,但是不能改变请求值和响应值;

Guess you like

Origin blog.csdn.net/fox9916/article/details/129672773