Filter 过滤器自定义及原理分析

目录

一、原因

二、自定义过滤器

1、web.xml配置方式

2、SpringBoot项目配置方式

方式1

方式2

方式3

方式4

三、源码解析

1、调用起点--StandardWrapperValve类

2、执行者--ApplicationFilterChain类


一、原因

虽然也工作了这么久,但是对过滤器具体实现原理,到底是怎么调用的,谁调用的,一直都是模棱两可。因此专门研究了一下,也记录下来给还不太了解的你做一个参考。

首先要知道的是Filter是Servlet规范的一部分,是Servlet容器(如Tomcat)实现的,并不是spring实现的。Filter接口是在tomcat的jar包中

 

二、自定义过滤器

我们先自定义一个自己的过滤器。

1、web.xml配置方式

 

 

2、SpringBoot项目配置方式

方式1

可以使用@WebFilter+@ServletComponentScan的方式

 

方式2

创建一个类去实现 ServletContextInitializer 接口,并把它注册为一个 Bean,Spring Boot 会负责调用这个接口的 onStartup 方法。

@Bean
public ServletContextInitializer servletContextInitializer() {
    return servletContext -> {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        FilterRegistration.Dynamic registration = servletContext.addFilter("filter", filter);
        registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/");
    };
}

方式3

可以使用FilterRegistrationBean 进行API级别的注册,注意,在这种情况下可以对Filter order进行设置,而使用spring的@Order注解是无效的

@Bean
public ServletRegistrationBean asyncServletServletRegistrationBean(){
    ServletRegistrationBean registrationBean =  new ServletRegistrationBean(new AsyncServlet(),"/");
    registrationBean.setName("MyAsyncServlet");
    registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return registrationBean;
}

FilterRegistrationBean其实也是通过 ServletContextInitializer 来实现的,它实现了 ServletContextInitializer 接口

方式4

直接实现Filter接口,并使用@Component注解标注为组件自动注入bean。

package com.demo.aop;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

@Component
public class DemoFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        System.out.println("DemoFilter:" + request.getRequestURL().toString());
        //执行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

特点:

可以拿到原始的http请求和响应的信息,但是拿不到真正处理这个请求的方法的信息

存在的问题:

通过Filter只能拿到http的请求和响应,只能从请求和响应中获得一些参数。当前发过来的这个请求实际上真正是由哪个控制器的哪个方法来处理的,在Filter里面是不知道的,因为javax.servlet.Filter是J2EE规范中定义的,J2EE规范里面实际上并不知道与spring相关的任何内容。而我们的controller实际上是spring mvc定义的一套机制。如果你需要这些信息,那么就需要使用拦截器Interceptor

 

 

三、源码解析

1、调用起点--StandardWrapperValve类

过滤器实现起点在ApplicationFilterChain类的doFilter()方法。StandardWrapperValve#invoke()方法调用ApplicationFilterChain#doFilter()方法,从此开启了filter过滤器链的调用。

2、执行者--ApplicationFilterChain类

在ApplicationFilterChain#doFilter()方法中调用internalDoFilter(request, response)

在internalDoFilter方法中,this.pos++通过自增实现自己调用自己后,可以获取过滤器链中下一个过滤器继续执行。

filter.doFilter(request, response, this)在调用过滤器的doFilter()方法,并将自己作为参数传入,然后在我们自定义的过滤器中执行filterChain.doFilter(servletRequest, servletResponse),从而实现自己调用自己。

debug示例

过滤器链调用示意图

在这里插入图片描述

过滤器链执行完后,会调用servlet.service(request, response)方法,这个servlet就是我们最熟悉的SpringMVC的DispatchServlet()

 

至此就实现了,浏览器发送http请求到达tomcat,tomcat调用filter过滤器链,过滤器链执行完后再调用SpringMVC中DispatchServlet类的service方法,从而实现对Controller的调用,最后再层层返回给浏览器,完成整个调用过程。

 

 

 

 

 

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值