Java组件(2)——Filter的原理和应用

JavaWeb的三大组件分别是: Servlet 程序、Listener 监听器、Filter 过滤器,我们这篇文章主要探索Filter。

Java组件(1)——Servlet

Java组件(2)——Filter的原理和应用

Java组件(3)——Listener的原理和应用

一、简介

  Filter的基本功能是对 Servlet 容器调用 Servlet (JSP)的过程进行拦截, 从而在 Servlet 处理请求前和 Servlet 响应请求后实现一些特殊的功能。它的作用主要分两点:拦截请求,过滤响应。

针对这两点作用,我们衍生了很多使用场景:

  • 过滤关键字、鉴权、拦截资源
  • 日记操作、事务管理、限流

二、原理

Filter 程序是一个实现了 Filter 接口的 Java 类,与 Servlet 程序相似,它由 Servlet 容器进行调用和执行。在 Servlet API 中定义了三个接口类来开供开发人员编写 Filter 程序: Filter、FilterChain、FilterConfig,Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源: Jsp、 Servlet,、静态图片文件、静态 html 文件等。而在SpringBoot 中我们只需配置中要注册了bean(FilterRegistrationBean),就自动添加了过滤器,支持web Filter 排序的使用。

当在 web.xml 中注册了一个 Filter 来对某个 Servlet 程序进行拦截处理时,这个Filter 就成了 Tomcat 与该 Servlet 程序的通信线路上的一道关卡,该 Filter 可以对Servlet 容器发送给 Servlet 程序的请求和 Servlet 程序回送给 Servlet 容器的响应进行拦截,可以决定是否将请求继续传递给 Servlet 程序,以及对请求和相应信息是否进行修改。在一个 web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以对一个或一组 Servlet 程序进行拦截。若有多个 Filter 程序对某个 Servlet 程序的访问过程进行拦截,当针对该 Servlet 的访问请求到达时,web 容器将把这多个 Filter 程序组合成一个 Filter 链(过滤器链)。Filter 链中各个 Filter 的拦截顺序与它们在应用程序的 web.xml 中映射的顺序一致。

三、Filter 的生命周期

1)在服务器启动时,filter 被创建并初始化,执行 init()方法。
2)请求通过 filter 时执行 doFilter 方法。
3)服务器停止时,调用 destroy 方法。

四、FilterChain 的过滤器链

多过滤器的所所有过滤器和资源都在一个线程中执行,并且使用的是一个request对象,以配置的顺序先后执行。

在这里插入图片描述

五、Filter、FilterChain、FilterConfig

Filter

一个 Filter 程序就是一个 Java 类,这个类必须实现 Filter 接口。javax.servlet.Filter 接口中定义了三个方法:init、doFilter、destory。

init

public voic init(FilterConfig filterConfig) throws ServletException
  • 在 Web 应用程序启动时,Web 容器根据 web.xml 文件的配置信息来创建每个注册的 Filter 的实例对象,并将保存在内存中。
  • Web 容器创建 Filter 的实例对象后,将立即调用该 Filter 对象的 init 方法。init 方法在 Filter 生命周期中仅被执行一次,Web 容器在调用 init 方法时,会传递一个包含 Filter 的配置和运行环境信息的 FilterConfig 对象。
  • 可以在 init 方法中完成与构造方法类似的初始化功能,要注意的是:如果初始化代码要使用到 FilterConfig 对象,这些代码只能在 init 方法中编写,而不能在构造方法中编写(尚未调用 init 方法,即并没有创建 FilterConfig 对象,要使用它则必然出错)。

doFilter

当一个 Filter 对象能够拦截访问请求时,Servlet 容器将调用 Filter 对象的 doFilter 方法。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException.ServletException

其中,参数 request 和 response 为 Web 容器或 Filter 链中上一个 Filter 传递过来的请求和响应对象;参数 chain 为代表当前 Filter 链的对象。

destroy

该方法在 Web 容器卸载 Filter 对象之前被调用,也仅执行一次。可以完成与 init 方法相反的功能,释放被该 Filter 对象打开的资源,例如:关闭数据库连接和 IO 流。

FilterChain

public void doFilter(ServletRequest request, ServletResponse response) throws java.io.IOException.ServletException

这个接口只定义了一个 doFilter 方法。FilterChain接口的 doFilter 方法用于通知 Web 容器把请求交给 Filter 链中的下一个 Filter 去处理,如果当前调用此方法的 Filter 对象是Filter 链中的最后一个 Filter,那么将把请求交给目标 Servlet 程序去处理。

FilterConfig

Servlet 规范将代表 ServletContext 对象和 Filter 的配置参数信息都封装到一个称为 FilterConfig 的对象中。FilterConfig 接口则用于定义 FilterConfig 对象应该对外提供的方法,以便在 Filter 程序中可以调用这些方法来获取 ServletContext 对象,以及获取在 web.xml 文件中为 Filter 设置的友好名称和初始化参数。

六、Filter的注册映射

注册 Filte

一个 <filter> 元素用于注册一个 Filter。其中,<filter-name> 元素是必需的,<filter-class> 元素也是必需的,<init-param> 元素是可选的,可以有多个 < init-param> 元素。

<filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>FirstFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>GB2312</param-value>
    </init-param>
</filter>

映射 Filter

<filter-mapping> 元素用于设置一个 Filter 所负责拦截的资源。一个 Filter 拦截的资源可以通过两种方式来指定:资源的访问请求路径和 Servlet 名称。

//指定资源的访问路径
<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
/*:表示拦截所有的访问请求。
/filter/*:表示拦截 filter 目录下的所有访问请求
/test.html:表示拦截根目录下以 test.html 为资源名的访问请求

//指定 Servlet 的名称
<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <servlet-name>default></servlet-name>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

七、Filter 程序示例

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
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;
 
public class FirstFilter implements Filter {
    private FilterConfig filterConfig = null;
    String paramValue = null;
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
        paramValue = filterConfig.getInitParameter("encoding");
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("begin headers-------------------");
        Enumeration<?> headerNames = ((HttpServletRequest)request).getHeaderNames();
        
        while(headerNames.hasMoreElements()) {
            String headerName = (String)headerNames.nextElement();
            System.out.println(headerName + ": " + ((HttpServletRequest)request).getHeader(headerName));
        }
        System.out.println("end headers-------------------");
        
        //在调用目标前写入响应内容
        response.setContentType("text/html; charset=gb2312");
        PrintWriter out = response.getWriter();
        out.println("IP地址为:" + request.getRemoteHost() + "<br>");
 
        chain.doFilter(request, response);
        
        //在目标返回后写入响应内容
        out.println("<br>名称为encoding的初始化参数的值为:" + paramValue);
        out.println("<br>当前Web程序的真实路径为:" + filterConfig.getServletContext().getRealPath("/"));
        
        //out.println("<br>修改了test.html文件!");
    }
    
    @Override
    public void destroy() {
        this.filterConfig = null;
    }
}

 


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值