Filter过滤器工作原理

article/2025/9/6 13:57:51

Filter过滤器工作原理

Filter简介

Filter也称之为过滤器,它是Servlet技术中最激动人心的技术之一,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp,
Servlet, 静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等
一些高级功能。
  Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter
技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,Filter接口源代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package javax.servlet;import java.io.IOException;public interface Filter {default void init(FilterConfig filterConfig) throws ServletException {}void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;default void destroy() {}
}

Filter工作原理

Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,
都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
​ 调用目标资源之前,让一段代码执行。
​ 是否调用目标资源(即是否让用户访问web资源)。
​ 调用目标资源之后,让一段代码执行。
  web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个
doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,
否则web资源不会被访问。

Spring中的filter过滤器

在这里插入图片描述

Spring的web包中中有很多过滤器,这些过滤器无一例外的继承了Filter接口,实现的方式大致可以分为以下几类:

  • 直接实现Filter,这一类过滤器只有CompositeFilter;
  • 继承抽象类GenericFilterBean,该类实现了javax.servlet.Filter,这一类的过滤器只有一个,即DelegatingFilterProxy;
  • 继承抽象类OncePerRequestFilter,该类为GenericFilterBean的直接子类,这一类过滤器包括CharacterEncodingFilter、HiddenHttpMethodFilter、HttpPutFormContentFilter、RequestContextFilter和ShallowEtagHeaderFilter;
  • 继承抽象类AbstractRequestLoggingFilter,该类为OncePerRequestFilter的直接子类,这一类过滤器包括CommonsRequestLoggingFilter、Log4jNestedDiagnosticContextFilter和ServletContextRequestLoggingFilter。

本文要讲述的,即是GenericFilterBean、OncePerRequestFilter和AbstractRequestLoggingFilter。

GenericFilterBean

抽象类GenericFilterBean实现了javax.servlet.Filter、org.springframework.beans.factory.BeanNameAware、org.springframework.context.EnvironmentAware、org.springframework.web.context.ServletContextAware、org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean五个接口,作用如下:

​ (1) Filter,实现过滤器;

​ (2) BeanNameAware,实现该接口的setBeanName方法,便于Bean管理器生成Bean;

​ (3) EnvironmentAware,实现该接口的setEnvironment方法,指明该Bean运行的环境;

​ (4) ServletContextAware,实现该接口的setServletContextAware方法,指明上下文;

​ (5) InitializingBean,实现该接口的afterPropertiesSet方法,指明设置属性生的操作;

​ (6) DisposableBean,实现该接口的destroy方法,用于回收资源。

​ GenericFilterBean的工作流程是:init-doFilter-destory,其中的init和destory在该类中实现,doFilter在具体实现类中实现。init的代码如下:

/*** Standard way of initializing this filter.* Map config parameters onto bean properties of this filter, and* invoke subclass initialization.* @param filterConfig the configuration for this filter* @throws ServletException if bean properties are invalid (or required* properties are missing), or if subclass initialization fails.* @see #initFilterBean*/@Overridepublic final void init(FilterConfig filterConfig) throws ServletException {Assert.notNull(filterConfig, "FilterConfig must not be null");this.filterConfig = filterConfig;// Set bean properties from init parameters.PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);if (!pvs.isEmpty()) {try {BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());Environment env = this.environment;if (env == null) {env = new StandardServletEnvironment();}bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, env));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);}catch (BeansException ex) {String msg = "Failed to set bean properties on filter '" +filterConfig.getFilterName() + "': " + ex.getMessage();logger.error(msg, ex);throw new NestedServletException(msg, ex);}}// Let subclasses do whatever initialization they like.initFilterBean();if (logger.isDebugEnabled()) {logger.debug("Filter '" + filterConfig.getFilterName() + "' configured for use");}}

该方法来自于javax.servlet.Filter,即过滤器的初始化,它的主要工作集中于以下几行代码:

// 从properties文件中获取值,这里是web.xml  
PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);  
// 设置bean适配器  
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);  
// 设置上下文,这里的servletContext的设定继承自ServletContextAware的setter  
ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());  
// 将上下文信息和环境信息设置到bean适配器中,这里的environment来自于EnvironmentAware的setter  
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));  
// 初始化bean适配器  
initBeanWrapper(bw);  
// 将从properties中获取的资源放置到bean适配器  
bw.setPropertyValues(pvs, true);  
// 初始化bean  
initFilterBean();  

其中initFilterBean方法在两个位置起作用,一处是上文所述的init方法,另一处是afterPropertiesSet方法,在调用该方法前,需要保证用于Filter的所有的bean都已被设置,该方法由子类实现。

​ GenericFilterBean中包含一个内部私有类FilterConfigPropertyValues,主要用于将web.xml中定义的init-param的值取出。

OncePerRequestFilter

​ 抽象类oncePerRequestFilter继承自GenericFilterBean,它保留了GenericFilterBean中的所有方法并对之进行了扩展,在oncePerRequestFilter中的主要方法是doFilter,代码如下:

/** * This <code>doFilter</code> implementation stores a request attribute for * "already filtered", proceeding without filtering again if the * attribute is already there. * @see #getAlreadyFilteredAttributeName * @see #shouldNotFilter * @see #doFilterInternal */  public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)  throws ServletException, IOException {  if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {  throw new ServletException("OncePerRequestFilter just supports HTTP requests");  }  HttpServletRequest httpRequest = (HttpServletRequest) request;  HttpServletResponse httpResponse = (HttpServletResponse) response;  // 调用GenericFilterBean的getFilterName方法返回已过滤的属性名  String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();  if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {  // 未调用该过滤器或已过滤  filterChain.doFilter(request, response);  }  else {  // 进行过滤  request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);  try {  doFilterInternal(httpRequest, httpResponse, filterChain);  }  finally {  // Remove the "already filtered" request attribute for this request.  request.removeAttribute(alreadyFilteredAttributeName);  }  }  }  

在doFilter方法中,doFilterInternal方法由子类实现,主要作用是规定过滤的具体方法。

AbstractRequestLoggingFilter

AbstractRequestLoggingFilter继承了OncePerRequestFilter并实现了其doFilterInternal方法,该方法代码如下:

/** * Forwards the request to the next filter in the chain and delegates down to the subclasses to perform the actual * request logging both before and after the request is processed. * * @see #beforeRequest * @see #afterRequest */  @Override  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  throws ServletException, IOException {  if (isIncludePayload()) {  // 若日志中包含负载,则重置request  request = new RequestCachingRequestWrapper(request);  }  // 过滤前执行的方法  beforeRequest(request, getBeforeMessage(request));  try {  // 执行过滤  filterChain.doFilter(request, response);  }  finally {  // 过滤后执行的方法  afterRequest(request, getAfterMessage(request));  }  }  

doFilter方法中的beforeRequest和afterRequest方法由子类实现,RequestCachingRequestWrapper为AbstractRequestLoggingFilter的内部内,主要作用是重置request。

区别

我们在使用过滤器时,通常没必要知道GenericFilterBean、OncePerRequestFilter和AbstractRequestLoggingFilter,但不防碍我们了解这几个类,就上文所述,

AbstractRequestLoggingFilter继承自OncePerRequestFilter

OncePerRequestFilter继承自GenericFilterBean

所以我们知道,genericFilterBean是任何类型的过滤器的一个比较方便的超类,

这个类主要实现的就是从web.xml文件中取得init-param中设定的值,然后对Filter进行初始化(当然,其子类可以覆盖init方法)

OncePerRequestFilter继承自GenericFilterBean,那么它自然知道怎么去获取配置文件中的属性及其值,所以其重点不在于取值,而在于确保在接收到一个request后,每个filter只执行一次*它的子类只需要关注Filter的具体实现即doFilterInternal*。

AbstractRequestLoggingFilter是对OncePerRequestFilter的扩展,它除了遗传了其父类及祖先类的所有功能外,还在doFilterInternal中决定了在过滤之前和之后执行的事件,它的子类关注的是beforeRequest和afterRequest。

总体来说,这三个类分别执行了Filter的某部分功能,当然,具体如何执行由它们的子类规定,若你需要实现自己的过滤器,也可以根据上文所述继承你所需要的类。


http://chatgpt.dhexx.cn/article/uPLe1nU9.shtml

相关文章

Filter过滤器

文章目录 FilterFilter过滤器的简单说明Filter的执行顺序 Eclipse创建简单的Filter过滤器Filter过滤不到指定路径 Filter Filter过滤器的简单说明 1.过滤器是一个驻留在服务器端的web组件&#xff0c;可以截取客户端和服务器端之间的请求与响应的信息 2.过滤器Filter是对客户…

FilterChain 过滤器链和拦截路径

Filter 过滤器 Chain 链&#xff0c;链条 FilterChain 就是过滤器链&#xff08;多个过滤器如何一起工作&#xff09; Filter 的拦截路径 精确匹配&#xff1a; <url-pattern>/target.jsp</url-pattern>以上配置的路径&#xff0c;表示请求地址必须为&#xff1…

Filter 过滤器

一、Filter 过滤器概念 ① Filter 过滤器它是 JavaWeb 的三大组件之一 三大组件分别是&#xff1a;Servlet 程序、 Listener 监听器、 Filter 过滤器 ② 他是 JavaEE 的规范&#xff0c;也就是接口 ③ 作用&#xff1a;拦截请求&#xff0c;过滤响应 拦截请求常见的应用场景有&…

filter过滤器的概念

文章目录 1. 图示2. 什么是Filter3. 代码演示4. 使用场景&#xff1a;事务处理 1. 图示 2. 什么是Filter Filter也属于Servlet规范Filter开发步骤&#xff1a;新建类实现Filter接口&#xff0c;然后实现其中的三个方法&#xff1a;init、doFilter、destroy 配置Filter&#xf…

Filter 过滤器使用

一、什么是Filter过滤器 Filter 过滤器它是 JavaWeb 的三大组件之一。 三大组件分别是&#xff1a;Servlet 程序、Listener 监听器、Filter 过滤器 Filter 过滤器它是 JavaEE 的规范。也就是接口 Filter 过滤器它的作用是&#xff1a;拦截请求&#xff0c;过滤响应。 拦截…

Filter过滤器(超详细)

声明&#xff1a;本文是根据博主学习内容所整理得的笔记&#xff0c;仅作为交流学习使用&#xff0c;需要观看视频的请移步&#xff1a;http://www.atguigu.com/ 1.Filter &#xff1f;什么是过滤器 Filter 过滤器它是 JavaWeb 的三大组件之一。 三大组件分别是&#xff1a;S…

GitHub使用教程(完整教程)

第一步&#xff1a;进入官网 &#xff08;https://github.com/&#xff09; 第二步&#xff1a;新建账号——输入用户名&#xff0c;邮箱&#xff0c; 密码——邮箱确认——登录GitHub 第三步&#xff1a;创建仓库 第三步&#xff1a;查看仓库 第四步&#xff1a;实现本地项目…

Git和Github详细入门教程(别再跟我说你不会Git和Github)

前言&#xff1a;基础差建议先观看B站视频&#xff08;关键字&#xff1a;GitHub&#xff09;&#xff0c;该教程是根据视频教程而制。 文章目录 01.Git概述02.Git的本地仓库操作 Git的版本回退操作 03.远程仓库05.Git的分支操作06.冲突的产生与解决07.Git实用功能08.忽略文件0…

GitHub Actions 入门教程

https://jiangren.com.au/blog/github-actions 一、GitHub Actions 是什么&#xff1f; 大家知道&#xff0c;持续集成由很多操作组成&#xff0c;比如抓取代码、运行测试、登录远程服务器&#xff0c;发布到第三方服务等等。GitHub 把这些操作就称为 actions。 很多操作在不…

小白入门~ GitHub和Git超详细使用教程

https://github.com/ 这是GitHub的官方网站&#xff0c;在官网上可以注册属于自己的GitHub账号&#xff0c;网上是全英文的&#xff0c;对于英语不好的同学建议使用谷歌浏览器&#xff0c;谷歌浏览器可以翻译网页变为中文使用起来十分方便。 通过简单的步骤之后你就会有一个属于…

GitHub使用教程(项目下载)

1.登录GitHub后选择左上角搜索框&#xff08;以点餐系统为例&#xff09; 2.选择合适的项目进入 3.选择合适的项目进入后&#xff0c;点击Code 4.点击Download ZIP即可下载项目代码压缩包

github使用教程图文详解(一)[入门]

git的使用和踩坑 Git的注册下载本地github工具绑定ssh秘钥获取ssh秘钥官网绑定ssh秘钥 创建远程库初始化仓库设置全局签名和单仓库签名的作用单仓库签名全局用户签名 提交到本地仓库git区域的划分提交到缓存区提交本地仓库和备注提交总结注意: 提交到远程仓库克隆远程仓库总结 …

GitHub 的 10 分钟快速入门教程

Hello World 这一篇是 GitHub 的 10 分钟快速入门教程&#xff0c;因为找不到中文版&#xff0c;大橙子自己给大家翻译了一下。 Hello World 项目是计算机编程的一个历史悠久的传统。这一篇我们也通过这个简单的练习让你学习到新的知识。那么就让我们开始 GitHub 的学习旅程吧…

【Github教程】史上最全github使用方法:github入门到精通

【初识Github】 首先让我们大家一起喊一句“Hello Github”。YEAH!就是这样。 Git是一个分布式的版本控制系统,最初由Linus Torvalds编写,用作Linux内核代码的管理。在推出后,Git在其它项目中也取得了很大成功,尤其是在Ruby社区中。目前,包括Rubinius和Merb在内的很多知名…

Github和Git的基本教程,适合新手

借鉴了这个博主的笔记 观看了b站up主的视频 Github和Git的基本使用 Github一.基本概念二 .创建账号三.创建仓库四&#xff1a;仓库管理五.仓库主页英文介绍 Git一. Git优势二.下载地址三.基本信息设置四.工作区域&#xff08;上传文件到Github&#xff09;五.删除文件六. 修改…

github入门教程最全中文版(官方)

该的Hello World项目是计算机编程历史悠久的传统。这是一个简单的练习&#xff0c;可以让你在学习新东西时开始学习。让我们开始使用GitHub&#xff01; 您将学习如何&#xff1a; 创建和使用存储库启动并管理新分支对文件进行更改并将其作为提交推送到GitHub打开并合并拉取请…

github注册以及安装教程

github注册以及安装教程 首先&#xff0c;我们了解一下github.gitHub 是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持 git 作为唯一的版本库格式进行托管&#xff0c;故名 gitHub。github 于 2008 年 4 月 10 日正式上线&#xff0c;除了 git 代码仓库托管及基…

GitHub快速上手--GitHub高效操作教程

一、前言 如果你正在看我的这篇文章&#xff0c;说明你已经对GitHub有了一些基础的了解&#xff0c;下面我们将详细叙述每一步的操作&#xff0c;以保证你能够快速上手GitHub&#xff0c;完成对代码的管理。 二、创建仓库 登录GitHub账号&#xff0c;点击页面右上角的加号&am…

GitHub使用教程-官网指南

此文为GitHub官网操作示例&#xff0c;英文原版见下文或访问地址&#xff1a;Hello World GitHub Guides Hello World 十分钟教学指南 Hello World项目在计算机编程领域是一个历史悠久的传统。当你学习一些新的东西的时候&#xff0c;它是你开始学习的一个简单的练习。让我…

GitHub注册教程(图文详解)

一、注册github流程 1.首先进入github官网 https://github.com/ 2.点击绿色框Sign up for GitHub进行注册 3.注册页面第一栏email&#xff08;邮箱&#xff09;&#xff0c;第二栏password&#xff08;密码&#xff09;&#xff0c;第三栏username&#xff08;用户名&#xff…