本文主要介绍Java中过滤器和拦截器的使用。通过示例代码进行了非常详细的介绍,对于大家的学习或者工作都有一定的参考价值。有需要的朋友下面和边肖一起学习。
:
目录
1.过滤器)2。拦截器)3。区别3.11、不同的实现原理3.2不同的应用范围3.3不同的触发时序3.4不同的拦截请求范围3.5不同的Bean注入3.6不同的控制执行顺序。
1.过滤器 (Filter)
滤波器的配置相对简单。可以直接实现Filter接口,也可以通过@WebFilter注释拦截特定的URL。您可以看到过滤器接口中定义了三种方法。
Init():该方法在容器启动初始化过滤器时调用,在过滤器的整个生命周期中只会调用一次。注意:该方法必须成功执行,否则过滤器将不起作用。
DoFilter():容器中的每个请求都调用这个方法,FilterChain用于调用下一个过滤器Filter。
Destroy():当容器销毁过滤器实例时,调用该方法。一般情况下,资源在方法中被销毁或关闭,在过滤器的整个生命周期中只会被调用一次。
@组件
公共类MyFilter实现过滤器{
@覆盖
公共void init(filter config filter config)引发ServletException {
System.out.println('Filter前缀');
}
@覆盖
公共void do filter(servlet request servlet request,ServletResponse servletResponse,FilterChain filterChain)引发IOException,ServletException {
System.out.println('进程中的筛选器');
filter chain . do filter(servlet request,servlet response);
}
@覆盖
public void destroy() {
system . out . println(' Filter Filter ');
}
}
2.拦截器 (Interceptor)
拦截器是一个链式调用。一个应用中可以同时存在多个拦截器拦截器,一个请求可以触发多个拦截器,每个拦截器的调用会按照其声明顺序依次执行。首先,编写一个简单的拦截器处理类。请求的拦截是由HandlerInterceptor实现的。我们可以看到HandlerInterceptor接口中也定义了三个方法。
Pre-handle():这个方法将在处理请求之前被调用。注意:如果该方法的返回值为false,则视为当前请求结束,不仅会使自己的拦截器失效,还会导致其他拦截器停止执行。
PostHandle():只有preHandle()方法的返回值为true时才会执行。在控制器中的方法调用之后,DispatcherServlet在返回到呈现的视图之前被调用。有趣的是,postHandle()方法的调用顺序与preHandle()相反。首先声明的拦截器preHandle()方法首先执行,而后执行postHandle()方法。
AfterCompletion():只有preHandle()方法的返回值为true时才会执行。在整个请求结束时,DispatcherServlet呈现相应的视图并执行它。
@组件
公共类MyInterceptor实现HandlerInterceptor {
@覆盖
公共布尔预处理(HttpServletRequest请求、HttpServletResponse响应、对象处理程序)引发异常{
System.out.println('拦截器前缀');
返回true
}
@覆盖
公共void post handle(http servlet request请求、HttpServletResponse响应、对象处理程序、ModelAndView modelAndView)引发异常{
System.out.println(“进程中的拦截器”);
}
@覆盖
public void after completion(http servlet request请求、HttpServletResponse响应、对象处理程序、Exception ex)引发异常{
system . out . println(' after Interceptor ');
}
}
注册自定义拦截器处理类,通过addPathPatterns、excludePathPatterns等属性设置要拦截或排除的URL。
@配置
公共类MyMvcConfig实现WebMvcConfigurer {
@覆盖
public void addInterceptors(InterceptorRegistry注册表){
registry.addInterceptor(新的MyInterceptor())。addpath patterns('/* * ');
registry.addInterceptor(新的MyInterceptor1())。addpath patterns('/* * ');
}
}
3.区别
过滤器和拦截器都体现了AOP的编程思想,都可以实现登录、登录认证等功能,但两者有很多区别,下面就一一说明。
3.11、实现原理不同
与过滤器和拦截器的实现不同,过滤器基于函数回调,拦截器基于Java反射机制(动态代理)。这里,重点是滤镜!我们都在自定义过滤器中实现了doFilter()方法。这个方法有一个FilterChain参数,但它实际上是一个回调接口。ApplicationFilterChain是它的实现类,这个实现类里面还有一个doFilter()方法,就是回调方法。
公共接口筛选器链{
void do filter(servlet request var 1,ServletResponse var2)抛出IOException,ServletException
}
在ApplicationFilterChain中,我们可以获取我们的自定义xxxFilter类,在其内部回调方法doFilter()中调用每个自定义xxxFilter,并执行doFilter()方法。
公共最终类ApplicationFilterChain实现FilterChain {
@覆盖
public void do filter(servlet request请求,ServletResponse响应){
.//省略
internalDoFilter(请求,响应);
}
private void internal dofilter(servlet request请求,ServletResponse响应){
如果(位置编号){
//获取位置过滤器
ApplicationFilterConfig filter config=filters[pos];
filter filter=filter config . get filter();
.
filter.doFilter(请求,响应,this);
}
}
}
并且每个xxxFilter都会先执行自己的doFilter()过滤逻辑,最后在执行结束之前,执行filterchain.doFilter (servlet请求,servlet响应),即回调ApplicationFilterChain的doFilter()方法,从而循环执行实现函数的回调。
@覆盖
公共void do filter(servlet request servlet request,ServletResponse servletResponse,FilterChain filterChain)引发IOException,ServletException {
filter chain . do filter(servlet request,servlet response);
}
3.2 使用范围不同
我们看到过滤器实现了javax。Servlet.Filter接口,而这个接口是在Servlet规范中定义的,也就是说filter filter的使用依赖于Tomcat等容器,所以只能在web程序中使用。
拦截器是一个Spring组件,由Spring容器管理,不依赖于Tomcat等容器,可以单独使用。它不仅可以用在web程序中,还可以用在Application、Swing等程序中。
3.3 触发时机不同
Filter在请求进入容器之后、进入servlet之前对其进行预处理,请求在servlet处理之后结束。拦截器在请求进入servlet之后和进入控制器之前进行预处理,在控制器中呈现相应的视图之后请求结束。
3.4 拦截的请求范围不同
在顶部,我们同时配置了过滤器和拦截器,然后构建一个控制器来接收测试请求。
@控制器
@RequestMapping()
公共类测试{
@RequestMapping('/test1 ')
@ResponseBody
公共字符串test1(字符串a) {
System.out.println('我是控制者');
返回null
}
}
在项目启动过程中,发现过滤器的init()方法是随着容器的启动而初始化的。
这时浏览器发送一个请求,F12看到实际上有两个请求,一个是我们的自定义控制器请求,一个是访问静态图标资源的请求。
查看控制台的打印日志,如下所示:
执行顺序:过滤处理——拦截器前——我是控制者——拦截器处理——拦截器后处理。
过滤处理
拦截器前沿
拦截器正在处理
截击机后部
过滤处理
3.5 注入Bean情况不同
在实际的业务场景中,当应用于过滤器或拦截器时,将不可避免地引入一些服务服务来处理业务逻辑。
下边我们分别在过滤器和拦截器中都注入服务,看看有什么不同?
@组件
公共类TestServiceImpl实现测试服务{
@覆盖
公共void a() {
System.out.println('我是方法a’);
}
}
过滤器中注入服务,发起请求测试一下,日志正常打印出"我是方法一个。
@自动连线
私有测试服务
@覆盖
公共void do过滤器(servlet请求servlet请求,servlet响应servlet响应,FilterChain filterChain)引发IOException,ServletException {
过滤器处理中');
测试服务。a();
过滤器链。do过滤器(servlet请求,servlet响应);
}
过滤器处理中
我是方法A
拦截机前置
我是控制器
拦截机处理中
拦截机后置
在拦截器中注入服务,发起请求测试一下,竟然报错了,调试跟一下发现注入的服务怎么是空啊?
这是因为加载顺序导致的问题,拦截器加载的时间点在春天语境之前,而豆又是由春天进行管理。
拦截器:老子今天要进洞房;
春天:兄弟别闹,你媳妇我还没生出来呢!
解决方案也很简单,我们在注册拦截器之前,先将拦截机手动进行注入。注意:在registry.addInterceptor()注册的是getMyInterceptor()实例。
@配置
公共类MyMvcConfig实现webmvc配置器{
@Bean
公共我的拦截器getmy interceptor(){
System.out.println('注入了我的拦截者’);
返回新的我的拦截器();
}
@覆盖
public void addInterceptors(InterceptorRegistry注册表){
注册表。添加拦截器(getmy interceptor()).addpath模式('/* * ');
}
}
3.6 控制执行顺序不同
实际开发过程中,会出现多个过滤器或拦截器同时存在的情况,不过,有时我们希望某个过滤器或拦截器能优先执行,就涉及到它们的执行顺序。
过滤器用@订单注解控制执行顺序,通过@订单控制过滤器的级别,值越小级别越高越先执行。
@订单(已订购。最高优先级)
@组件
公共类我的过滤器2实现过滤器{}
拦截器默认的执行顺序,就是它的注册顺序,也可以通过命令手动设置控制,值越小越先执行。
@覆盖
public void addInterceptors(InterceptorRegistry注册表){
registry.addInterceptor(新的MyInterceptor2()).addPathPatterns('/** ').订单(2);
registry.addInterceptor(新的MyInterceptor1()).addPathPatterns('/** ').订单(1);
registry.addInterceptor(新的MyInterceptor()).addPathPatterns('/** ').顺序(3);
}
看到输出结果发现,先声明的拦截器预处理()方法先执行,而后处理()方法反而会后执行。
后处理()方法被调用的顺序跟预处理()居然是相反的!如果实际开发中严格要求执行顺序,那就需要特别注意这一点。
拦截器一前置
截击机2前置
拦截机前置
我是控制器
拦截机处理中
截击机2处理中
拦截器一处理中
拦截机后置
截击机2处理后
拦截器一处理后
那为什么会这样呢?得到答案就只能看源码了,我们要知道控制器中所有的请求都要经过核心组件调度员服务网路由,都会执行它的doDispatch()方法,而拦截器后处理()方法便是在其中调用的。
受保护的void do分派(http servlet请求请求,HttpServletResponse响应)引发异常{
尝试{
..
尝试{
//获取可以执行当前处理者的适配器
处理程序适配器ha=gethandler适配器(映射的处理程序。gethandler());
//如果处理程序支持,则处理上次修改的标头。
字符串方法=请求。get方法();
布尔isGet='GET ' .等于(方法);
if (isGet || 'HEAD ' .等于(方法)){
上次修改时间=ha。getlastmedified(请求,映射的处理程序。gethandler());
if (logger.isDebugEnabled()) {
伐木工。调试([' getRequestUri(request)']的最后修改的值为:'最后修改');
}
if(新的ServletWebRequest(请求,响应)。checkNotModified(last modified)是get){
返回;
}
}
//注意:执行拦截机中预处理()方法
如果(!映射的处理程序。applyprehandle(已处理的请求,响应)){
返回;
}
//注意:执行手柄[包括我们的业务逻辑,当抛出异常时会被尝试、抓住到】
mv=ha.handle(processedRequest,response,mapped handler。gethandler());
如果(异步管理器。isconcurrenthandlingstarted()){
返回;
}
applyDefaultViewName(已处理请求,mv);
//注意:执行拦截机中后处理方法【抛出异常时无法执行】
映射的处理程序。applyposthandle(已处理的请求、响应、mv);
}
}
..
}
看看两个方法applyPreHandle()、applyPostHandle()具体是如何被调用的,就明白为什么后处理()执行顺序是相反的了。
布尔applypprehandle(http servlet请求请求,HttpServletResponse响应)引发异常{
处理程序拦截器[]拦截器=this。获取拦截器();
如果(!ObjectUtils.isEmpty(拦截器)){
for(int I=0;我截击机。长度;this.interceptorIndex=i ) {
handler interceptor interceptor=interceptors[I];
如果(!interceptor.preHandle(请求、响应、this.handler)) {
this.triggerAfterCompletion(请求,响应,(异常)null);
返回错误的
}
}
}
返回真实的
}
void applyPostHandle(http servlet请求请求,HttpServletResponse响应,@Nullable ModelAndView mv)引发异常{
处理程序拦截器[]拦截器=this。获取拦截器();
如果(!ObjectUtils.isEmpty(拦截器)){
for(int I=拦截器。长度-1;I=0;- i) {
handler interceptor interceptor=interceptors[I];
interceptor.postHandle(请求、响应、this.handler、mv);
}
}
}
发现两个方法中在调用拦截器数组HandlerInterceptor[]时,循环的顺序竟然是相反的。导致后处理()方法执行的顺序相反。
到此这篇关于Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)中过滤器(过滤器)和拦截器(截击机)的使用的文章就介绍到这了,更多相关Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)过滤器和拦截器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。