Filter、Listener学习笔记

Filter 简介

  • Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。
  • 可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet。Servlet 过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。
  • Servlet 过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:
    • 在客户端的请求访问后端资源之前,拦截这些请求。
    • 在服务器的响应发送回客户端之前,处理这些响应。

Servlet 过滤器方法

过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:

序号 方法 & 描述
1 public void doFilter (ServletRequest, ServletResponse, FilterChain)

该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
2 public void init(FilterConfig filterConfig)

web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
3 public void destroy()

Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

快速入门

示例1

过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。Filter的执行顺序与在web.xml配置文件中的配置顺序一致,一般把Filter配置在所有的Servlet之前。

Input

web.xml

<filter>
    <!-- 声明Filter名字 -->
    <filter-name>demo01</filter-name>
    <!-- 对应的Filter类全名 -->
    <filter-class>my.stringbug.FilterDemo01</filter-class>
</filter>

<filter-mapping>
    <!-- 对应声明的Filter名字 -->
    <filter-name>demo01</filter-name>
    <!-- 过滤器的过滤路径 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

FilterDemo01.java

public class FilterDemo01 implements Filter {

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

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        System.out.println("FilterDemo01 过滤器给执行了 ~~");

        // 放行(假如没有放行,那么被该过滤器过滤的页面都不会有请求信息和响应信息)
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() { }
}

index.jsp

<body>
  <h1>Demo 01 ~~~~~</h1>
</body>

Output

控制台

FilterDemo01 过滤器给执行了 ~~

浏览器页面

Demo 01 ~~~~~

示例2

使用注解的方式进行声明,映射到对应的应用程序的部署描述符中的 Servlet 名称或 URL 模式。

Input

FilterDemo02.java

// "/*" 访问所有资源之前,都会执行该过滤器
@WebFilter("/*")
public class FilterDemo02 implements Filter {

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

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        System.out.println("FilterDemo02 过滤器给执行了 ~~");

        // 放行(假如没有放行,那么被该过滤器过滤的页面都不会有请求信息和响应信息)
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() { }
}

index.jsp

<body>
  <h1>Demo 02 ~~~~~</h1>
</body>

Output

控制台

FilterDemo02 过滤器给执行了 ~~

浏览器页面

Demo 02 ~~~~~

Filter 执行流程 & Filter 生命周期

Filter 执行流程

  • Filter 接口中有一个doFilter 方法,当咱们编写好 Filter,并配置对哪个 web 资源进行拦截后,web 服务器每次在调用 web 资源的 service 方法之前,都会先调用一下 Filter 的 doFilter 方法,因此,在该方法内编写代码可达到如下的:

    1. 调用目标资源之前,让一段代码执行;
    2. 是否调用目标资源,即是否让用户访问 web 资源;
    3. 调用目标资源之后,让一段代码执行。

  • web 服务器在调用 doFilter 方法时,会传递一个 filterChain 对象进来,filterChain 对象是 filter 接口中最重要的一个对象,它也提供了一个 doFilter 方法,开发人员可以根据需求决定是否调用此方法。如果调用该方法,则 web 服务器就会调用 web 资源的 service 方法,即 web 资源就会被访问;否则的话, web 资源就不会被访问。


Filter 生命周期

  1. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
  2. doFilter:每一次请求被拦截资源时,会执行。执行多次
  3. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源

Filter 配置说明

拦截路径配置

  1. 具体资源路径,如:/index.jsp
  2. 拦截某个目录,如:/directory1/directory2/*
  3. 后缀名拦截,如:*.html
  4. 拦截所有资源,如:/*

拦截方式配置

  1. 注解配置

    属性 类型 说明
    asyncSupported boolean 指定Filter是否支持异步模式
    dispatcherTypes DispatcherType[ ] 指定Filter对哪种方式的请求进行过滤。
    支持的属性:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST;
    默认过滤所有方式的请求
    filterName String Filter名称
    initParams WebInitParam[ ] 配置参数
    displayName String Filter显示名
    servletNames String[ ] 指定对哪些Servlet进行过滤
    urlPatterns/value String[ ] 两个属性作用相同,指定拦截的路径

  2. web.xml配置

    • <filter>指定一个过滤器。

      • <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
      • <filter-class>元素用于指定过滤器的完整的限定类名。
      • <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。
      • 在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。

    • <filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。

      • 一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
      • <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
      • <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)

    • <servlet-name>指定过滤器所拦截的Servlet名称。

    • <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。

      • <dispatcher>子元素可以设置的值及其意义
        1. REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
        2. INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
        3. FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
        4. ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

过滤器链

有多个过滤器,过滤器的执行顺序和拦截顺序说明。

过滤器先后顺序问题

  1. 注解配置:按照类名的字符串比较规则比较,值小的先执行。

    如: AFilter 和 BFilter,AFilter先执行。

  2. web.xml配置:谁定义在上边,谁先执行


过滤器执行顺序

如果有两个过滤器:过滤器1和过滤器2

过滤器1

@WebFilter(value = "/index.jsp")
public class FilterDemo04 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        System.out.println("小明通过过滤器1,去服务器了");

        // Filter1 放行
        filterChain.doFilter(servletRequest, servletResponse);

        System.out.println("小明通过过滤器1,从服务器回来了");
    }

    @Override
    public void destroy() { }
}

过滤器2

@WebFilter(value = "/index.jsp")
public class FilterDemo05 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException {
        System.out.println("小明通过过滤器2,去服务器了");

        // Filter2 放行
        filterChain.doFilter(servletRequest, servletResponse);

        System.out.println("小明通过过滤器2,从服务器回来了");
    }

    @Override
    public void destroy() { }
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Filter And Listener Demo</title>
  </head>
  <body>
    <% System.out.println("服务器资源被访问了"); %>
  </body>
</html>

启动服务器,访问index.jsp资源,控制台输出:

小明通过过滤器1,去服务器了
小明通过过滤器2,去服务器了
服务器资源被访问了
小明通过过滤器2,从服务器回来了
小明通过过滤器1,从服务器回来了

Listener 学习笔记

简介

监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。监听器可以用来检测网站的在线人数,统计网站的访问量等

监听器涉及三个组件:事件源事件对象事件监听器

当事件源发生某个动作的时候,它会调用事件监听器的方法,并在调用事件监听器方法的时候把事件对象传递进去。


ServletContextListener

ServletContextListener:监听ServletContext对象的创建和销毁

void contextDestroyed(ServletContextEvent sce)
// ServletContext对象被销毁之前会调用该方法

void contextInitialized(ServletContextEvent sce)
// ServletContext对象创建后会调用该方法

快速入门

  1. 实现ServletContextListener接口
  2. 复写方法
  3. 配置(web.xml配置或注解配置)

实现ServletContextListener接口,复写方法

public class ContextLoaderListener implements ServletContextListener {
    /**
     * 监听ServletContext对象创建的。ServletContext对象在服务器启动后自动创建。
     */
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        // ServletContext对象创建后会调用该方法
        System.out.println("ServletContext 对象被创建了");
    }

    /**
     * 在服务器关闭后,ServletContext对象被销毁。当服务器正常关闭后,该方法会被执行。
     */
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        // ServletContext对象被销毁之前会调用该方法
        System.out.println("ServletContext 对象被销毁了");
    }
}

web.xml配置

<listener>
    <listener-class>my.listener.ContextLoaderListener</listener-class>
</listener>

注解配置:在实现监听接口的方法上面添加注解

@WebListener("my/listener/contextLoaderListener")

正常的启动服务器,和关闭服务器:控制台输出

启动服务器

ServletContext 对象被创建了

关闭服务器

ServletContext 对象被销毁了

参考文献

  1. Servlet 编写过滤器 | 菜鸟教程
  2. 详述 Java 中过滤器 Filter 的工作原理及使用方法
  3. Servlet3.0下@WebFilter注解配置Filter
  4. 监听器入门看这篇就够了
上一篇:EventTarget.addEventListener 和 EventTarget.removeEventListener 用法详解


下一篇:编写高质量代码改善C#程序的157个建议——建议113:声明变量前考虑最大值