Spring Boot

SpringBoot2.x过滤器OncePerRequestFi

2019-10-25  本文已影响0人  小胖学编程

JAVA && Spring && SpringBoot2.x — 学习目录

SpringBoot2.x(Spring)含有内置的Filter。即OncePerRequestFilter顾名思义:仅执行一次的Filter。图1是OncePerRequestFilter的子类:

图1-SpringBoot2.x的OncePerRequestFilter子类关系图.png

在Spring中,Filter默认继承OncePerRequestFilter类。来过滤请求。

1. OncePerRequestFilter存在的意义

OncePerRequestFilter是在一次外部请求中只过滤一次。对于服务器内部之间的forward等请求,不会再次执行过滤方法。

在SpringBoot2.x环境下,服务器内部转发(forward)一个请求,代码如图2所示:

图二-转发请求.png
  1. 自定义实现Filter接口的类,在过滤请求时打印日志。结果如图三所示:
图三-打印Filter请求.png

根据上图所示,实际上请求在服务器内部转发时,并未进行过滤。可以看到上,实现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所示。

图4-核心源码.png

采用的是模板方法模式,子类实现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所示。

图5-init模板方法模式源码.png

initFilterBean()方法,在两个地方使用到,一个是init方法中,一个是afterPropertiesSet方法(即Filter若放到Spring容器,初始化时执行该方法)。实际上会执行两次初始化方法,如图6所示:

图6-初始化方法会执行两次.png

SpringBoot2.x将Filter加入到容器的几种方法

2.2 过滤方法

以SpringBoot2.x自动装载的编码过滤器为例,如图7所示:

源码:org.springframework.web.filter.CharacterEncodingFilter

图7-CharacterEncodingFilter过滤器核心代码.png

源码:org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration

图8-SpringBoot将其加入到容器中.png

总结:在Spring环境中,推荐实现OncePerRequestFilter类,而非实现原生的Filter接口。

上一篇下一篇

猜你喜欢

热点阅读