SpringBoot2.x过滤器OncePerRequestFi
JAVA && Spring && SpringBoot2.x — 学习目录
SpringBoot2.x(Spring)
含有内置的Filter
。即OncePerRequestFilter
顾名思义:仅执行一次的Filter
。图1是OncePerRequestFilter
的子类:
在Spring中,Filter默认继承OncePerRequestFilter类。来过滤请求。
1. OncePerRequestFilter存在的意义
OncePerRequestFilter
是在一次外部请求中只过滤一次。对于服务器内部之间的forward
等请求,不会再次执行过滤方法。
在SpringBoot2.x环境下,服务器内部转发(forward)
一个请求,代码如图2所示:
- 自定义实现
Filter
接口的类,在过滤请求时打印日志。结果如图三所示:
根据上图所示,实际上请求在服务器内部转发时,并未进行过滤。可以看到上,实现Filter
接口,也会在一次请求中只过滤一次。
实际上,
OncePerRequestFilter
是为了兼容不同的web 容器,也就是说其实不是所有的容器都过滤一次。Servlet版本不同,执行的过程也不同。例如:在Servlet2.3中,Filter会过滤一切请求,包括服务器内部使用forward和<%@ include file=/login.jsp%>的情况,但是在servlet2.4中,Filter默认只会过滤外部请求。
对于异步请求(即为避免线程阻塞,需要委托另一个线程处理),也只过滤一次请求。
【小家Spring】——关于OncePerRequestFilter
源码:org.springframework.web.filter.OncePerRequestFilter#doFilter
中,通过更改request中的Filter状态,防止内部请求时多次调用Filter,核心代码如图4所示。
采用的是模板方法模式,子类实现org.springframework.web.filter.OncePerRequestFilter#doFilterInternal
方法。对请求进行过滤。
在Spring环境中若想使用Filter,建议继承
OncePerRequestFilter
,而非原生的Servlet Filter接口。
2. OncePerRequestFilter方法
OncePerRequestFilter
是采用的模板方法模式,子类需要实现父类定义的钩子方法(算法逻辑父类已经实现),便可以进行过滤。
2.1 初始化方法
org.springframework.web.filter.GenericFilterBean#init
中实现init方法,子类若是想执行init方法。需要实现org.springframework.web.filter.GenericFilterBean#initFilterBean
默认的钩子方法,源码如图5所示。
但initFilterBean()
方法,在两个地方使用到,一个是init
方法中,一个是afterPropertiesSet
方法(即Filter若放到Spring容器,初始化时执行该方法)。实际上会执行两次初始化方法,如图6所示:
SpringBoot2.x将Filter加入到容器的几种方法
2.2 过滤方法
以SpringBoot2.x自动装载的编码过滤器为例,如图7所示:
源码:org.springframework.web.filter.CharacterEncodingFilter
源码:org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
总结:在Spring环境中,推荐实现OncePerRequestFilter类,而非实现原生的Filter接口。