JavaWeb开发基础Servlet事件和监听器

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。

事件和监听器

事件是指在程序运行过程中发生的特定动作或情况。比如:

  • 用户操作,如点击按钮、输入文本

  • 系统操作,如文件读取完成、网络连接断开

  • 应用程序内部的状态变化,如对象属性改变、方法调用

监听器是一个接口或类,用于定义在特定事件发生时要执行的操作。监听器会“监听”特定的事件,当事件发生时,监听器中的相应方法会被调用,从而执行预定义的操作。

事件和监听器是相辅相成的,它们的工作原理如下:

  1. 事件源:触发事件的来源。例如,按钮是事件源,点击按钮会触发点击事件
  2. 事件对象:当事件发生时,事件源会创建一个事件对象,包含有关事件的信息
  3. 注册监听器:监听器需要注册到事件源,以便监听特定的事件。注册后,事件源会在事件发生时通知监听器
  4. 事件处理:当事件发生时,事件源会调用监听器中的相应方法,传递事件对象,从而执行预定义的操作

Servlet Event Class

事件(Event)是一个类,封装了与特定事件相关的信息。

基本是构造方法和get方法:

  1. ServletRequestEvent

```java public class ServletRequestEvent extends EventObject { private static final long serialVersionUID = 1L; private final ServletRequest request;

   public ServletRequestEvent(ServletContext sc, ServletRequest request) {
       super(sc);
       this.request = request;
   }

   public ServletRequest getServletRequest() {
       return this.request;
   }

   public ServletContext getServletContext() {
       return (ServletContext) super.getSource();
   }

} ```

  1. ServletRequestAttributeEvent

```java public class ServletRequestAttributeEvent extends ServletRequestEvent { private static final long serialVersionUID = 1L; private final String name; private final Object value;

   public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) {
       super(sc, request);
       this.name = name;
       this.value = value;
   }

   public String getName() {
       return this.name;
   }

   public Object getValue() {
       return this.value;
   }

} ```

  1. ServletContextEvent

```java public class ServletContextEvent extends EventObject { private static final long serialVersionUID = 1L;

   public ServletContextEvent(ServletContext source) {
       super(source);
   }

   public ServletContext getServletContext() {
       return (ServletContext) super.getSource();
   }

} ```

  1. ServletContextAttributeEvent

```java public class ServletContextAttributeEvent extends ServletContextEvent { private static final long serialVersionUID = 1L; private final String name; private final Object value;

   public ServletContextAttributeEvent(ServletContext source, String name, Object value) {
       super(source);
       this.name = name;
       this.value = value;
   }

   public String getName() {
       return this.name;
   }

   public Object getValue() {
       return this.value;
   }

} ```

  1. HttpSessionEvent

```java public class HttpSessionEvent extends EventObject { private static final long serialVersionUID = 1L;

   public HttpSessionEvent(HttpSession source) {
       super(source);
   }

   public HttpSession getSession() {
       return (HttpSession) super.getSource();
   }

} ```

  1. HttpSessionBindingEvent

```java public class HttpSessionBindingEvent extends HttpSessionEvent { private static final long serialVersionUID = 1L; private final String name; private final Object value;

   public HttpSessionBindingEvent(HttpSession session, String name, Object value) {
       super(session);
       this.name = name;
       this.value = value;
   }

   public String getName() {
       return this.name;
   }

   public Object getValue() {
       return this.value;
   }

} ```

Servlet Listener Interface

监听器(Listener)是一个接口,定义了处理这些事件的方法。

  1. ServletRequestListener

java public interface ServletRequestListener extends EventListener { void requestDestroyed(ServletRequestEvent sre); void requestInitialized(ServletRequestEvent sre); }

  1. ServletRequestAttributeListener

java public interface ServletRequestAttributeListener extends EventListener { void attributeAdded(ServletRequestAttributeEvent srae); void attributeRemoved(ServletRequestAttributeEvent srae); void attributeReplaced(ServletRequestAttributeEvent srae); }

  1. ServletContextListener

java public interface ServletContextListener extends EventListener { void contextInitialized(ServletContextEvent sce); void contextDestroyed(ServletContextEvent sce); }

  1. ServletContextAttributeListener

java public interface ServletContextAttributeListener extends EventListener { void attributeAdded(ServletContextAttributeEvent scae); void attributeRemoved(ServletContextAttributeEvent scae); void attributeReplaced(ServletContextAttributeEvent scae); }

  1. HttpSessionListener

java public interface HttpSessionListener extends EventListener { void sessionCreated(HttpSessionEvent se); void sessionDestroyed(HttpSessionEvent se); }

  1. HttpSessionBindingListener

java public interface HttpSessionBindingListener { void valueBound(HttpSessionBindingEvent event); void valueUnbound(HttpSessionBindingEvent event); }

  1. HttpSessionActivationListener

java public interface HttpSessionActivationListener { void sessionWillPassivate(HttpSessionEvent se); void sessionDidActivate(HttpSessionEvent se); }

  1. HttpSessionAttributeListener

java public interface HttpSessionAttributeListener extends EventListener { void attributeAdded(HttpSessionBindingEvent se); void attributeRemoved(HttpSessionBindingEvent se); void attributeReplaced(HttpSessionBindingEvent se); }

Event与Listener

一个事件可以对应多个监听器,它们是怎么关联的?查看ServletRequestListener源码:

package javax.servlet;

import java.util.EventListener;

public interface ServletRequestListener extends EventListener {
    void requestDestroyed(ServletRequestEvent var1);
    // 入参是ServletRequestEvent
    void requestInitialized(ServletRequestEvent var1);
}

ServletRequestListener接口的方法入参是ServletRequestEvent类型,也就是说,在调用监听器ServletRequestListener的requestInitialized方法时,会传入事件对象ServletRequestEvent。

每种类型的事件都有对应的监听器接口,Servlet容器会根据事件类型调用相应的监听器方法。以下是一个简化的示例,展示了Servlet容器如何根据事件类型调用相应的监听器方法:

1.定义事件和监听器

import java.util.EventListener;
import java.util.EventObject;

// 定义ServletRequestEvent类
public class ServletRequestEvent extends EventObject {
    private static final long serialVersionUID = 1L;
    private final ServletRequest request;

    public ServletRequestEvent(ServletContext sc, ServletRequest request) {
        super(sc);
        this.request = request;
    }

    public ServletRequest getServletRequest() {
        return this.request;
    }

    public ServletContext getServletContext() {
        return (ServletContext) super.getSource();
    }
}

// 定义ServletRequestListener接口
public interface ServletRequestListener extends EventListener {
    void requestDestroyed(ServletRequestEvent sre);
    void requestInitialized(ServletRequestEvent sre);
}

2.定义ServletContext和ServletRequest

public class ServletContext {
    // 简化的ServletContext实现
}

public class ServletRequest {
    // 简化的ServletRequest实现
}

3.定义Servlet容器

import java.util.ArrayList;
import java.util.List;

public class SimpleServletContainer {
    private List<ServletRequestListener> requestListeners = new ArrayList<>();

    // 注册监听器
    public void addServletRequestListener(ServletRequestListener listener) {
        requestListeners.add(listener);
    }

    // 模拟请求初始化
    public void initializeRequest(ServletRequest request, ServletContext context) {
        // 创建事件对象
        ServletRequestEvent event = new ServletRequestEvent(context, request);
        // 遍历监听器,调用方法,传入事件对象
        for (ServletRequestListener listener : requestListeners) {
            listener.requestInitialized(event);
        }
    }

    // 模拟请求销毁
    public void destroyRequest(ServletRequest request, ServletContext context) {
        ServletRequestEvent event = new ServletRequestEvent(context, request);
        for (ServletRequestListener listener : requestListeners) {
            listener.requestDestroyed(event);
        }
    }
}

4.实现监听器

@WebListener
public class MyServletRequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("Request initialized: " + sre.getServletRequest());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("Request destroyed: " + sre.getServletRequest());
    }
}

监听器可以通过注解@WebListener或在web.xml中进行配置:

  • 使用注解:

java @WebListener public class MyServletRequestListener implements ServletRequestListener { // 实现接口方法 }

  • 在web.xml中配置:

xml <listener> <listener-class>com.example.MyServletRequestListener</listener-class> </listener>

5.测试代码

public class Main {
    public static void main(String[] args) {
        // 创建Servlet容器
        SimpleServletContainer container = new SimpleServletContainer();

        // 创建ServletContext和ServletRequest
        ServletContext context = new ServletContext();
        ServletRequest request = new ServletRequest();

        // 注册监听器
        container.addServletRequestListener(new MyServletRequestListener());

        // 模拟请求初始化和销毁
        container.initializeRequest(request, context);
        container.destroyRequest(request, context);
    }
}

运行结果:

Request initialized: ServletRequest@1a2b3c4d
Request destroyed: ServletRequest@1a2b3c4d

解释:

  1. 事件创建:

  2. 当请求初始化时,容器创建一个ServletRequestEvent对象,并将ServletContext和ServletRequest作为参数传递给事件对象的构造函数

  3. 同样,当请求销毁时,容器再次创建一个ServletRequestEvent对象

  4. 事件通知:

  5. 容器遍历所有注册的监听器,检查它们是否实现了ServletRequestListener接口

  6. 对于实现了ServletRequestListener接口的监听器,容器调用它们的requestInitialized或requestDestroyed方法,并传递ServletRequestEvent对象

在实际的Servlet容器(如Tomcat、Jetty等)中,事件的触发和监听器的调用是由容器内部的代码实现的。容器会在特定事件发生时创建相应的事件对象,并调用注册的监听器方法。通过这种机制,开发者可以在特定事件发生时执行自定义逻辑,从而实现更灵活和强大的功能。换句话说,这些监听器的工作方式类似于钩子函数(Hook),通过实现这些监听器接口,我们可以在Servlet生命周期的不同阶段,自定义处理逻辑。

参考资料:

https://www.javatpoint.com/Event-and-Listener-in-Servlet

ChatGPT