参考:SpringBoot中filter的使用详解及原理_u014627099的博客-CSDN博客_filter springboot
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
运行结果:
可以看到代码执行流程,首先请求会被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.apache.catalina.connector.RequestFacade@5d98f8e7 http://localhost:8080/api/filterTest.json /api/filterTest.json 过滤。。。 first filter 2
可以看到没有进入controller。因为命中率这里的逻辑:
也就是说:这里断开了,没有了后续。
3. SessionFilter拦截非法请求
![]()
![]()
因为从整个请求链路来看:经过了firstfilter-》scondfilter -》sessionfilter
首先secondfilter没有拦截,因为url没有包含“Test”字符,所以到达了sessionfilter
但是被sessionfilter拦截了。因为needFilter是true,需要拦截
4. 请求被filter拦截。通过arthas确认是哪一个filter拦截的。
![]()
开启arthas监听模式:在Arthas里面,把整个请求经过哪些filter处理,都打印成树。这里找下嵌套最深层
可以看到这里是: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
上述结论一致。