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.apac
he.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
上述结论一致。