1. 处理请求流程

Request -》 filter1 -〉 filter2 -》 controller

                                                        |
Request《- filter1 《- filter2 《-   controller

2. filter原理【本质就是责任链设计】

请求会经过一个个编写的filter,最后进入controller 。然后返回一个个filter,最后给到请求方

3. 源码:https://github.com/bailuoxi66/snapUpDemo/tree/master/springBoot-Redis-Demo/springboot-filter 

4. 代码相关

1. 要想使用filter,需要写一个方法继承Filter类。我们自己写了两个Filter类。其中

@Order里面的数字越小代表越先被该filter过滤
@WebFilter代表这是个Filter类,以便于启动类进行扫描的时候确认

2. FirstFilter
package com.example.springbootfilter.filterInfo;

import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * @author :luoyu
 * @version :1.0
 * @date : 2021/12/31 10:47 上午
 * @description
 */


@Order(1)
@WebFilter(filterName = "firstFilter", urlPatterns = "/*")
public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("first filter 1");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("first filter 2");
    }

    @Override
    public void destroy() {
    }
}
3. SecondFilter
package com.example.springbootfilter.filterInfo;

import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @author :luoyu
 * @version :1.0
 * @date : 2021/12/31 10:47 上午
 * @description
 */

@Order(2)
@WebFilter(filterName = "secondFilter", urlPatterns = "/*")
public class SecondFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("second filter 1");

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        System.out.println("before:" + servletRequest);
        System.out.println(request.getRequestURL());
        String uri = request.getRequestURI();
        System.out.println(uri);
        if (uri.contains("Test")){
            System.out.println("过滤。。。");
            servletResponse.getWriter().write("secondfilter already");
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("after:" + servletResponse);
        System.out.println("second filter 2");
    }

    @Override
    public void destroy() {
    }
}
4. SessionFilter
package com.example.springbootfilter.filterInfo;

import org.springframework.core.annotation.Order;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author :luoyu
 * @version :1.0
 * @date : 2021/12/31 12:01 下午
 * @description
 */
@Order(3)
@WebFilter(filterName = "sessionFilter",urlPatterns = {"/*"})
public class SessionFilter implements Filter {

    //不需要登录就可以访问的路径(比如:注册登录等)
    String[] includeUrls = new String[]{"/login","/test1"};


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String uri = request.getRequestURI();

        System.out.println("filter url:"+uri);
        //是否需要过滤
        boolean needFilter = isNeedFilter(uri);

        if (!needFilter) { //不需要过滤直接传给下一个过滤器
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            response.getWriter().write("sessionFilter already");
        }
    }


    /**
     * 是否需要过滤
     * @params [uri]
     * @return boolean
     * @author luoyu
     * @date 2021/12/31 1:35 下午
     **/
    public boolean isNeedFilter(String uri) {

        for (String includeUrl : includeUrls) {
            if(includeUrl.equals(uri)) {
                return false;
            }
        }

        return true;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

4. controller类

5. SpringBoot的主入口方法。注意:因为我们使用的是注解注入Filter,

所以需要加入:@ServletComponentScan

@SpringBootApplication
@ServletComponentScan
public class SpringbootFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootFilterApplication.class, args);
    }

}

6. 运行结果

1. 正常没有过滤逻辑

请求:http://localhost:8080/test1

运行结果:

springboot责任链模式 spring 责任链_java

可以看到代码执行流程,首先请求会被FirstFilter截获,打印出first filter1,然后执行filterChain.doFilter(servletRequest, servletResponse),这句话代表请求会转发给过滤器链上的下一个对象,也就是SecondFilter,所以打印出second filter 1 。接下来执行SecondFilter里面的 filterChain.doFilter(servletRequest, servletResponse) ,请求会转发给下一个对象,到达SessionFilter打印filter url:/test1.然后根据是否过滤逻辑,发现不需要过滤直接给到下一个filter。调用filterChain.doFilter(servletRequest, servletResponse),但是没有其他filter了。所以会转发给controller。打印出controller里面对应方法的内容【“method in controller”】,接下来去虚拟机栈栈帧里面获取信息,调用SecondFilter打印出second filter 2. 同理调用FirstFilter打印出first filter 2。   

2. filter过滤逻辑
请求:http://localhost:8080/api/filterTest.json
运行结果:
first filter 1
second filter 1
before:org.apac

he.catalina.connector.RequestFacade@5d98f8e7 http://localhost:8080/api/filterTest.json /api/filterTest.json 过滤。。。 first filter 2

可以看到没有进入controller。因为命中率这里的逻辑:

springboot责任链模式 spring 责任链_java_02

也就是说:这里断开了,没有了后续。  

3. SessionFilter拦截非法请求

springboot责任链模式 spring 责任链_System_03

 

springboot责任链模式 spring 责任链_java_04

springboot责任链模式 spring 责任链_System_05

 

因为从整个请求链路来看:经过了firstfilter-》scondfilter -》sessionfilter

首先secondfilter没有拦截,因为url没有包含“Test”字符,所以到达了sessionfilter

但是被sessionfilter拦截了。因为needFilter是true,需要拦截

4. 请求被filter拦截。通过arthas确认是哪一个filter拦截的。

springboot责任链模式 spring 责任链_System_06

 

springboot责任链模式 spring 责任链_System_07

开启arthas监听模式:在Arthas里面,把整个请求经过哪些filter处理,都打印成树。这里找下嵌套最深层

springboot责任链模式 spring 责任链_spring_08

可以看到这里是:SessionFilter里面进行了拦截 

arthas:所有结果

[arthas@86617]$ trace javax.servlet.Filter *
Press Q or Ctrl+C to abort.
Affect(class count: 18 , method count: 100) cost in 266 ms, listenerId: 1
`---ts=2021-12-31 14:08:34;thread_name=http-nio-8080-exec-4;id=30;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@5c1bd44c
    `---[6.468228ms] org.springframework.web.filter.OncePerRequestFilter:doFilter()
        +---[0.888623ms] org.springframework.web.filter.OncePerRequestFilter:getAlreadyFilteredAttributeName() #97
        |   `---[0.851397ms] org.springframework.web.filter.OncePerRequestFilter:getAlreadyFilteredAttributeName()
        |       `---[0.800084ms] org.springframework.web.filter.OncePerRequestFilter:getFilterName() #170
        |           `---[0.07793ms] org.springframework.web.filter.GenericFilterBean:getFilterName()
        |               `---[0.024575ms] javax.servlet.FilterConfig:getFilterName() #298
        +---[0.019792ms] javax.servlet.ServletRequest:getAttribute() #98
        +---[2.108542ms] org.springframework.web.filter.OncePerRequestFilter:skipDispatch() #100
        |   `---[2.07759ms] org.springframework.web.filter.OncePerRequestFilter:skipDispatch()
        |       +---[1.977538ms] org.springframework.web.filter.OncePerRequestFilter:isAsyncDispatch() #127
        |       |   `---[1.94646ms] org.springframework.web.filter.OncePerRequestFilter:isAsyncDispatch()
        |       |       +---[0.013899ms] javax.servlet.http.HttpServletRequest:getDispatcherType() #146
        |       |       `---[0.072898ms] javax.servlet.DispatcherType:equals() #146
        |       `---[0.02551ms] javax.servlet.http.HttpServletRequest:getAttribute() #130
        +---[0.105523ms] org.springframework.web.filter.OncePerRequestFilter:shouldNotFilter() #100
        |   `---[0.031155ms] org.springframework.web.filter.OncePerRequestFilter:shouldNotFilter()
        +---[0.027592ms] javax.servlet.ServletRequest:setAttribute() #115
        +---[2.759263ms] org.springframework.web.filter.OncePerRequestFilter:doFilterInternal() #117
        |   `---[2.69305ms] org.springframework.web.filter.CharacterEncodingFilter:doFilterInternal()
        |       +---[0.056953ms] org.springframework.web.filter.CharacterEncodingFilter:getEncoding() #192
        |       |   `---[0.020965ms] org.springframework.web.filter.CharacterEncodingFilter:getEncoding()
        |       +---[0.058125ms] org.springframework.web.filter.CharacterEncodingFilter:isForceRequestEncoding() #194
        |       |   `---[0.016392ms] org.springframework.web.filter.CharacterEncodingFilter:isForceRequestEncoding()
        |       +---[0.038208ms] javax.servlet.http.HttpServletRequest:setCharacterEncoding() #195
        |       +---[0.035288ms] org.springframework.web.filter.CharacterEncodingFilter:isForceResponseEncoding() #197
        |       |   `---[0.011489ms] org.springframework.web.filter.CharacterEncodingFilter:isForceResponseEncoding()
        |       `---[2.412639ms] javax.servlet.FilterChain:doFilter() #201
        |           `---[2.367289ms] org.springframework.web.filter.OncePerRequestFilter:doFilter()
        |               +---[0.092118ms] org.springframework.web.filter.OncePerRequestFilter:getAlreadyFilteredAttributeName() #97
        |               |   `---[0.067511ms] org.springframework.web.filter.OncePerRequestFilter:getAlreadyFilteredAttributeName()
        |               |       `---[0.046879ms] org.springframework.web.filter.OncePerRequestFilter:getFilterName() #170
        |               |           `---[0.025428ms] org.springframework.web.filter.GenericFilterBean:getFilterName()
        |               |               `---[0.007377ms] javax.servlet.FilterConfig:getFilterName() #298
        |               +---[0.011038ms] javax.servlet.ServletRequest:getAttribute() #98
        |               +---[0.140236ms] org.springframework.web.filter.OncePerRequestFilter:skipDispatch() #100
        |               |   `---[0.115496ms] org.springframework.web.filter.OncePerRequestFilter:skipDispatch()
        |               |       +---[0.072747ms] org.springframework.web.filter.OncePerRequestFilter:isAsyncDispatch() #127
        |               |       |   `---[0.041142ms] org.springframework.web.filter.OncePerRequestFilter:isAsyncDispatch()
        |               |       |       +---[0.008436ms] javax.servlet.http.HttpServletRequest:getDispatcherType() #146
        |               |       |       `---[0.006054ms] javax.servlet.DispatcherType:equals() #146
        |               |       `---[0.010302ms] javax.servlet.http.HttpServletRequest:getAttribute() #130
        |               +---[0.034537ms] org.springframework.web.filter.OncePerRequestFilter:shouldNotFilter() #100
        |               |   `---[0.009114ms] org.springframework.web.filter.OncePerRequestFilter:shouldNotFilter()
        |               +---[0.019467ms] javax.servlet.ServletRequest:setAttribute() #115
        |               +---[1.971268ms] org.springframework.web.filter.OncePerRequestFilter:doFilterInternal() #117
        |               |   `---[1.937453ms] org.springframework.web.filter.FormContentFilter:doFilterInternal()
        |               |       +---[0.196208ms] org.springframework.web.filter.FormContentFilter:parseIfNecessary() #88
        |               |       |   `---[0.171456ms] org.springframework.web.filter.FormContentFilter:parseIfNecessary()
        |               |       |       `---[0.148937ms] org.springframework.web.filter.FormContentFilter:shouldParse() #99
        |               |       |           `---[0.122507ms] org.springframework.web.filter.FormContentFilter:shouldParse()
        |               |       |               +---[0.020572ms] javax.servlet.http.HttpServletRequest:getContentType() #113
        |               |       |               +---[0.033034ms] javax.servlet.http.HttpServletRequest:getMethod() #114
        |               |       |               `---[0.020836ms] org.springframework.util.StringUtils:hasLength() #115
        |               |       +---[0.011308ms] org.springframework.util.CollectionUtils:isEmpty() #89
        |               |       `---[1.685984ms] javax.servlet.FilterChain:doFilter() #93
        |               |           `---[1.664666ms] org.springframework.web.filter.OncePerRequestFilter:doFilter()
        |               |               +---[0.081575ms] org.springframework.web.filter.OncePerRequestFilter:getAlreadyFilteredAttributeName() #97
        |               |               |   `---[0.065688ms] org.springframework.web.filter.OncePerRequestFilter:getAlreadyFilteredAttributeName()
        |               |               |       `---[0.051453ms] org.springframework.web.filter.OncePerRequestFilter:getFilterName() #170
        |               |               |           `---[0.030805ms] org.springframework.web.filter.GenericFilterBean:getFilterName()
        |               |               |               `---[0.007209ms] javax.servlet.FilterConfig:getFilterName() #298
        |               |               +---[0.010989ms] javax.servlet.ServletRequest:getAttribute() #98
        |               |               +---[0.13897ms] org.springframework.web.filter.OncePerRequestFilter:skipDispatch() #100
        |               |               |   `---[0.122124ms] org.springframework.web.filter.OncePerRequestFilter:skipDispatch()
        |               |               |       +---[0.078663ms] org.springframework.web.filter.OncePerRequestFilter:isAsyncDispatch() #127
        |               |               |       |   `---[0.053971ms] org.springframework.web.filter.OncePerRequestFilter:isAsyncDispatch()
        |               |               |       |       +---[0.005793ms] javax.servlet.http.HttpServletRequest:getDispatcherType() #146
        |               |               |       |       `---[0.013142ms] javax.servlet.DispatcherType:equals() #146
        |               |               |       `---[0.011082ms] javax.servlet.http.HttpServletRequest:getAttribute() #130
        |               |               +---[0.021786ms] org.springframework.web.filter.OncePerRequestFilter:shouldNotFilter() #100
        |               |               |   `---[0.005747ms] org.springframework.web.filter.OncePerRequestFilter:shouldNotFilter()
        |               |               +---[0.012466ms] javax.servlet.ServletRequest:setAttribute() #115
        |               |               +---[1.293744ms] org.springframework.web.filter.OncePerRequestFilter:doFilterInternal() #117
        |               |               |   `---[1.262514ms] org.springframework.web.filter.RequestContextFilter:doFilterInternal()
        |               |               |       +---[0.021243ms] org.springframework.web.context.request.ServletRequestAttributes:<init>() #96
        |               |               |       +---[0.278449ms] org.springframework.web.filter.RequestContextFilter:initContextHolders() #97
        |               |               |       |   `---[0.256751ms] org.springframework.web.filter.RequestContextFilter:initContextHolders()
        |               |               |       |       +---[0.132398ms] javax.servlet.http.HttpServletRequest:getLocale() #112
        |               |               |       |       +---[0.025818ms] org.springframework.context.i18n.LocaleContextHolder:setLocale() #112
        |               |               |       |       +---[0.017864ms] org.springframework.web.context.request.RequestContextHolder:setRequestAttributes() #113
        |               |               |       |       `---[0.016344ms] org.apache.commons.logging.Log:isTraceEnabled() #114
        |               |               |       +---[0.705757ms] javax.servlet.FilterChain:doFilter() #100
        |               |               |       |   `---[0.661857ms] com.example.springbootfilter.filterInfo.FirstFilter:doFilter()
        |               |               |       |       `---[0.569476ms] javax.servlet.FilterChain:doFilter() #27
        |               |               |       |           `---[0.532086ms] com.example.springbootfilter.filterInfo.SecondFilter:doFilter()
        |               |               |       |               +---[0.037252ms] javax.servlet.http.HttpServletRequest:getRequestURL() #30
        |               |               |       |               +---[0.012403ms] javax.servlet.http.HttpServletRequest:getRequestURI() #31
        |               |               |       |               `---[0.266668ms] javax.servlet.FilterChain:doFilter() #38
        |               |               |       |                   `---[0.228648ms] com.example.springbootfilter.filterInfo.SessionFilter:doFilter()
        |               |               |       |                       +---[0.009811ms] javax.servlet.http.HttpServletRequest:getRequestURI() #29
        |               |               |       |                       +---[0.089258ms] com.example.springbootfilter.filterInfo.SessionFilter:isNeedFilter() #33
        |               |               |       |                       |   `---[0.058013ms] com.example.springbootfilter.filterInfo.SessionFilter:isNeedFilter()
        |               |               |       |                       `---[0.030816ms] javax.servlet.http.HttpServletResponse:getWriter() #38
        |               |               |       +---[0.148522ms] org.springframework.web.filter.RequestContextFilter:resetContextHolders() #103
        |               |               |       |   `---[0.083649ms] org.springframework.web.filter.RequestContextFilter:resetContextHolders()
        |               |               |       |       +---[0.023226ms] org.springframework.context.i18n.LocaleContextHolder:resetLocaleContext() #120
        |               |               |       |       `---[0.009855ms] org.springframework.web.context.request.RequestContextHolder:resetRequestAttributes() #121
        |               |               |       +---[0.00996ms] org.apache.commons.logging.Log:isTraceEnabled() #104
        |               |               |       `---[0.013286ms] org.springframework.web.context.request.ServletRequestAttributes:requestCompleted() #107
        |               |               `---[0.019486ms] javax.servlet.ServletRequest:removeAttribute() #121
        |               `---[0.008947ms] javax.servlet.ServletRequest:removeAttribute() #121
        `---[0.010701ms] javax.servlet.ServletRequest:removeAttribute() #121

springboot责任链模式 spring 责任链_java_09

上述结论一致。