全面了解Servlet规范中定义的监听器Listener

导读:本篇文章讲解 全面了解Servlet规范中定义的监听器Listener,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1、监听器的基本知识

1.1、概念

  监听器就是一个实现特定接口的普通java程序(事件监听器),这个程序专门用于监听另一个java对象(事件源)的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。Java的事件监听器是由事件类和监听接口组成,其中,JAVA中监听接口是继承java.util.EventListener的类,事件类继承java.util.EventObject的类。

1.2、监听器三要素

  在监听器中涉及到了三个重要的组件,即事件源,事件对象和事件监听器。当事件源发生某个动作的时候,它会调用事件监听器的方法,并在调用事件监听器方法的时候把事件对象传递进去。在监听器中就可以通过事件对象获取得到事件源,从而对事件源进行操作。

2、Servlet规范中定义的监听器

  在Servlet规范中定义的监听器有很多,分类的方式也有很多,这里我将以事件源对象的角度进行分类:

  • ServletContext相关监听器:
  1. ServletContextListener
    ServletContext域对象监听器
  2. ServletContextAttributeListener
    ServletContext域对象存储数据监听器,即监听其中数据变化的监听器
  • ServletRequest相关监听器:
  1. ServletRequestListener
    ServletRequest域对象监听器
  2. ServletRequestAttributeListener
    ServletRequest域对象存储数据监听器,即监听其中数据变化的监听器
  • HttpSession相关监听器:
  1. HttpSessionListener
    HttpSession域对象监听器,其中关联的事件对象是HttpSessionEvent。
  2. HttpSessionIdListener
    HttpSession域对象中ID变化的监听器。和HttpSessionListener 一样,关联的事件对象是HttpSessionEvent。
  3. HttpSessionActivationListener
    HttpSession域对象中的JavaBean对象对钝化和恢复的监听器。和HttpSessionListener 、HttpSessionIdListener 一样,关联的事件对象是HttpSessionEvent。
  4. HttpSessionAttributeListener
    HttpSession域对象存储数据监听器,即监听其中数据变化的监听器。其中关联的事件对象是HttpSessionBindingEvent。
  5. HttpSessionBindingListener
    HttpSession域对象中的JavaBean对象对绑定和解绑的监听器。和HttpSessionAttributeListener 一样,关联的事件对象是HttpSessionBindingEvent。
2.1、ServletContext相关的监听器
2.1.1、ServletContext的初始化、销毁监听器

  ServletContext的初始化、销毁监听器由ServletContext、ServletContextListener、ServletContextEvent组成。其中ServletContextEvent对应事件对象,ServletContextListener对应事件监听器接口,ServletContext对应事件源。

  在ServletContextListener事件监听器接口中,定义了两个方法,其中contextInitialized()方法用来监听ServletContext对象的初始化事件,contextDestroyed()方法用来监听ServletContext对象的销毁事件。两个方法的参数都是ServletContextEvent,即事件对象。

ServletContextListener事件监听器接口:

package javax.servlet;

import java.util.EventListener;

public interface ServletContextListener extends EventListener {

    public void contextInitialized(ServletContextEvent sce);

    public void contextDestroyed(ServletContextEvent sce);
}

ServletContextEvent事件对象:

package javax.servlet;

public class ServletContextEvent extends java.util.EventObject {

    private static final long serialVersionUID = 1L;


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

    public ServletContext getServletContext() {
        return (ServletContext) super.getSource();
    }
}
2.1.2、ServletContext中属性变化的监听器

  ServletContext中属性变化的监听器由ServletContext中的对象(可能是任意的JavaBean对象)、ServletContextAttributeListener、ServletContextAttributeEvent组成。其中ServletContextAttributeEvent对应事件对象,ServletContextAttributeListener对应事件监听器接口,ServletContext中的对象对应事件源。

  在ServletContextAttributeListener事件监听器接口中,定义了三个方法,其中attributeAdded()方法用来监听ServletContext对象中新的属性被新增加时的事件,attributeRemoved()方法用来监听ServletContext对象中原有的属性被移除时的事件。attributeReplaced()方法用来监听ServletContext对象中原有属性被替换时的事件。这三个方法的参数都是ServletContextAttributeEvent,即事件对象。

ServletContextAttributeListener事件监听器接口:

package javax.servlet;

import java.util.EventListener;

public interface ServletContextAttributeListener extends EventListener {

    public void attributeAdded(ServletContextAttributeEvent scae);

    public void attributeRemoved(ServletContextAttributeEvent scae);

    public void attributeReplaced(ServletContextAttributeEvent scae);
}

ServletContextAttributeEvent事件对象:

package javax.servlet;

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;
    }
}
2.2、ServletRequest相关的监听器

  ServletRequest的监听器和ServletContext的监听器类似,也是包括了ServletRequest对象的初始化、销毁监听器和ServletRequest对象中属性变化的监听器。除了事件源本身不一样外,其他的用法和ServletContext监听器基本一样。

2.2.1、ServletRequest的初始化、销毁监听器

  ServletRequest的初始化、销毁监听器由ServletRequest、ServletRequestListener、ServletRequestEvent组成。其中ServletRequestEvent对应事件对象,ServletRequestListener对应事件监听器接口,ServletContext对应事件源。

  在ServletRequestListener事件监听器接口中,定义了两个方法,其中requestInitialized()方法用来监听ServletRequest对象的初始化事件,requestDestroyed()方法用来监听ServletRequest对象的销毁事件。两个方法的参数都是ServletRequestEvent,即事件对象。

  ServletRequestListener、ServletRequestEvent源码和ServletContext中的类似,略……。

2.2.2、ServletRequest中属性变化的监听器

  ServletRequest中属性变化的监听器由ServletRequest中的对象(可能是任意的JavaBean对象)、ServletRequestAttributeListener、ServletRequestAttributeEvent组成。其中ServletRequestAttributeEvent对应事件对象,ServletRequestAttributeListener对应事件监听器接口,ServletRequest中的对象对应事件源。

  在ServletRequestAttributeListener事件监听器接口中,定义了三个方法,其中attributeAdded()方法用来监听ServletRequest对象中新的属性被新增加时的事件,attributeRemoved()方法用来监听ServletRequest对象中原有的属性被移除时的事件。attributeReplaced()方法用来监听ServletRequest对象中原有属性被替换时的事件。这三个方法的参数都是ServletRequestAttributeEvent,即事件对象。

  ServletRequestAttributeListener、ServletRequestAttributeEvent源码和ServletContext中的类似,略……。

2.3、HttpSession相关的监听器

  HttpSession的监听器除了和上述ServletContext、ServletRequest对象类似的监听器外,还提供了一些其他的监听器,比如HttpSessionActivationListener、HttpSessionBindingListener等,而且HttpSession的监听器在实际的应用开发过程中,使用的也是比较多的。下面我们就分别来了解学习相关的监听器对象。

2.3.1、HttpSession的初始化、销毁监听器

  HttpSession的初始化、销毁监听器由HttpSession、HttpSessionListener、HttpSessionEvent组成。其中HttpSessionEvent对应事件对象,HttpSessionListener对应事件监听器接口,HttpSession对应事件源。

  在HttpSessionListener事件监听器接口中,定义了两个方法,其中sessionCreated()方法用来监听HttpSession对象的初始化事件,sessionDestroyed()方法用来监听HttpSession对象的销毁事件。两个方法的参数都是HttpSessionEvent,即事件对象。

HttpSessionListener事件监听器接口:

package javax.servlet.http;

import java.util.EventListener;

public interface HttpSessionListener extends EventListener {

    public void sessionCreated(HttpSessionEvent se);

    public void sessionDestroyed(HttpSessionEvent se);
}

HttpSessionEvent事件对象:

package javax.servlet.http;

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

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

    public HttpSession getSession() {
        return (HttpSession) super.getSource();
    }
}
2.3.2、HttpSession域对象的ID变化监听器

 &mesp;HttpSessionIdListener监听器和HttpSessionListener的用法基本一样,其中,事件对象也一样都是HttpSessionEvent。在HttpSessionIdListener监听器接口中定义了sessionIdChanged()方法,用来监听HttpSession域对象中的ID变化。

HttpSessionIdListener事件监听器接口:

package javax.servlet.http;

import java.util.EventListener;

public interface HttpSessionIdListener extends EventListener {

    public void sessionIdChanged(HttpSessionEvent se, String oldSessionId);
}
2.3.3、HttpSession中属性变化(新增、移除、替换)的监听器

  HttpSession中属性变化的监听器由HttpSession中的对象(可能是任意的JavaBean对象)、HttpSessionAttributeListener、HttpSessionBindingEvent组成。其中HttpSessionBindingEvent对应事件对象,HttpSessionAttributeListener对应事件监听器接口,HttpSession中的对象对应事件源。

  在HttpSessionAttributeListener事件监听器接口中,定义了三个方法,其中attributeAdded()方法用来监听HttpSession对象中新的属性被新增加时的事件,attributeRemoved()方法用来监听HttpSession对象中原有的属性被移除时的事件。attributeReplaced()方法用来监听HttpSession对象中原有属性被替换时的事件。这三个方法的参数都是HttpSessionBindingEvent,即事件对象。

  细心的同学已经发现了,在监听HttpSession域对象属性变化的监听对象中,对应的事件对象命名和前面讲过的ServletContextAttributeEvent、ServletRequestAttributeEvent命名规则不太一样了,因为前面都是*AttributeEvent的格式,而这里使用了HttpSessionBindingEvent类,这是因为HttpSession域对象属性监听器和HttpSessionBindingListener域对象属性解绑和绑定监听器使用了同一个类作为事件对象,而且遵循了HttpSessionBindingListener域对象属性解绑和绑定监听器的命名规则。

HttpSessionAttributeListener事件监听器接口:

package javax.servlet.http;

import java.util.EventListener;

public interface HttpSessionAttributeListener extends EventListener {

    public void attributeAdded(HttpSessionBindingEvent se);

    public void attributeRemoved(HttpSessionBindingEvent se);

    public void attributeReplaced(HttpSessionBindingEvent se);
}

HttpSessionBindingEvent 事件对象:

package javax.servlet.http;

public class HttpSessionBindingEvent extends HttpSessionEvent {

    private static final long serialVersionUID = 1L;

    /* The name to which the object is being bound or unbound */
    private final String name;

    /* The object is being bound or unbound */
    private final Object value;

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

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

    @Override
    public HttpSession getSession() {
        return super.getSession();
    }

    public String getName() {
        return name;
    }

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

2.3.4、HttpSession中JavaBean对象对绑定和解绑的监听器

  HttpSessionBindingListener监听器主要用来对HttpSession中JavaBean对象的绑定和解绑进行监听。在功能上,和HttpSessionAttributeListener监听器有点儿类似。区别在于:

  1. HttpSessionBindingListener是用来监听HttpSession中的JavaBean对象,而HttpSessionAttributeListener是用来监听域对象HttpSession的,具体是域对象HttpSession中的属性变化,即前者的事件源是JavaBean对象,而后者是域对象HttpSession;
  2. HttpSessionBindingListener监听器接口是由JavaBean对象来继承和实现的,且不需要在web.xml中进行配置,而而HttpSessionAttributeListener监听器需要专门的监听器类来继承和实现,且该监听器类需要在web.xml中配置(也可以使用注解)才能生效。

  在HttpSessionBindingListener事件监听器接口中,定义了两个方法,其中valueBound()方法用来监听HttpSession中JavaBean对象的绑定事件,即指将JavaBean对象存放在session域对象的事件;valueUnbound()方法用来监听HttpSession中JavaBean对象解绑的事件,即将JavaBean对象从session域对象中删除的事件。这两个方法的参数都是HttpSessionBindingEvent,即事件对象,和HttpSessionAttributeListener监听器的事件对象使用同一个类表示。

HttpSessionBindingListener事件监听器接口:

package javax.servlet.http;

import java.util.EventListener;

public interface HttpSessionBindingListener extends EventListener {

    public void valueBound(HttpSessionBindingEvent event);

    public void valueUnbound(HttpSessionBindingEvent event);
}
2.3.5、HttpSession中JavaBean对象对钝化和恢复的监听器

  HttpSessionActivationListener监听器主要用来对HttpSession中JavaBean对象的钝化和恢复进行监听。在用法上,和HttpSessionBindingListener 监听器有点儿类似,首先是他们的事件源都是JavaBean对象,所以需要JavaBean对象实现HttpSessionActivationListener接口来实现,其次,这类监听器也不需要再web.xml中配置才生效。
  JavaBean对象钝化指的是Tomcat正常关闭时,那么Session对象中的JavaBean对象会被钝化,数据会保存到Tomcat的work目录下;JavaBean对象恢复指的是再次打开Tomcat的时候恢复work目录下这些数据。

  在HttpSessionActivationListener事件监听器接口中,定义了两个方法,其中sessionWillPassivate()方法用来监听HttpSession中JavaBean对象的钝化事件,即指Tomcat正常关闭时,将JavaBean对象存放会保存到Tomcat的work目录下的事件;sessionDidActivate()方法用来监听HttpSession中JavaBean对象恢复的事件,即指再次打开Tomcat的时候,恢复work目录下数据的事件。这两个方法的参数都是HttpSessionEvent,即事件对象,和HttpSessionIdListener、HttpSessionListener监听器的事件对象使用同一个类表示。

HttpSessionActivationListener 事件监听器接口:

package javax.servlet.http;

import java.util.EventListener;

public interface HttpSessionActivationListener extends EventListener {

    public void sessionWillPassivate(HttpSessionEvent se);

    public void sessionDidActivate(HttpSessionEvent se);
}

3、监听器使用示例

  在Gitee中,我准备了一个完整的Listener示例的Demo,感兴趣的童鞋,可以使用,地址:https://gitee.com/hsh2015/servlet-learning/tree/master/servlet-listener

  在该示例中,我们把这篇文章提到的所有监听器都准备了示例,因为好多监听器的用法都是类似的,所以这里以Session相关的监听器为主来演示。

首先项目结构如下所示:

在这里插入图片描述
在这里插入图片描述
  其中、context、request、session包分别对应了ServletContext、ServletRequest、HttpSession相关监听器,其中在session.bean子包下包含的是HttpSession的HttpSessionActivationListener和HttpSessionBindingListener的示例;controller包,存放了用于测试controller方法;WEB-INF/pages目录下,保存了一个测试使用的页面。

3.1、MyHttpSessionListener监听器示例

  首先,我们演示MyHttpSessionListener监听器,因为在初始化HttpSession的时候,也可能会触发其他监听器,为了避免其他监听器干扰,@ServletComponentScan注解的包路径设置成:com.hsh.listener.session.other,即只扫描该目录下的监听器配置(@WebListener注解的类)。

在Application.class类中的配置如下:

//可以扫描到com.hsh.listener包下的监听器类
@ServletComponentScan(value = { "com.hsh.listener.session.other" })
@ComponentScan
@SpringBootApplication
public class ListenerApplication extends SpringBootServletInitializer {

	public static void main(String[] args) {
		SpringApplication.run(ListenerApplication.class, args);
	}
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(ListenerApplication.class);
	}
}

在IndexController.class测试类中添加如下方法:

@Controller
public class IndexController {
	
	@RequestMapping("/index")
    public String session(HttpServletRequest request, HttpServletResponse response){
        return "SessionTest";
    }
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request, HttpServletResponse response){
		HttpSession session = request.getSession();
        session.invalidate();
        System.out.println("Session对象被销毁了");
        return "SessionTest";
    }
    //其他方法省略了
}

MyHttpSessionListener 监听器代码如下所示:

@WebListener
public class MyHttpSessionListener implements HttpSessionListener, HttpSessionIdListener{

	@Override
	public void sessionCreated(HttpSessionEvent se) {
		System.out.println("MyHttpSessionListener-sessionCreated()方法,HttpSession初始化……");
	}
	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		System.out.println("MyHttpSessionListener-sessionDestroyed()方法,HttpSession销毁……");
	}
	@Override
	public void sessionIdChanged(HttpSessionEvent se, String oldSessionId) {
		System.out.println("MyHttpSessionListener-sessionIdChanged()方法,HttpSessionID发生变化……");
	}
}

访问http://localhost:8080/servlet-listener/index,控制台打印日志如下:
在这里插入图片描述
页面如下:
在这里插入图片描述

点击“销毁Session”按钮,实际上调用了http://localhost:8080/servlet-listener/logout,控制台打印日志如下:

销毁Session后,返回页面时,又创建了一个Session,所以又除非了一次初始化操作。

在这里插入图片描述

3.2、MyHttpSessionAttributeListener监听器示例

  MyHttpSessionAttributeListener监听器代码如下:

@WebListener
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {

	@Override
	public void attributeAdded(HttpSessionBindingEvent se) {
		System.out.println("MyHttpSessionAttributeListener-attributeAdded()方法,HttpSession属性对象添加……");
	}

	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) {
		System.out.println("MyHttpSessionAttributeListener-attributeRemoved()方法,HttpSession属性对象移除……");
	}

	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) {
		System.out.println("MyHttpSessionAttributeListener-attributeReplaced()方法,HttpSession属性对象替换……");
	}

}

在IndexController.class测试类中添加如下方法:

@RequestMapping("/testSessionAttribute")
    public String testSessionAttribute(HttpServletRequest request, HttpServletResponse response){
		HttpSession session = request.getSession();
		System.out.println("########## 添加  ##############");
		session.setAttribute("username", "张三");
		session.setAttribute("age", 15);
		System.out.println("########### 移除  #############");
		session.removeAttribute("username");
		System.out.println("########## 替换  ##############");
		session.setAttribute("age", 16);
        return "SessionTest";
    }

访问http://localhost:8080/servlet-listener/testSessionAttribute,控制台打印日志如下:

因为第一次请求会触发MyHttpSessionListener监听器的初始化方法,所以会打印日志。

在这里插入图片描述

3.3、MyUserOfBinding监听器示例

  MyUserOfBinding监听器,监听的是JavaBean对象。这里把抽象出了一个MyUser对象,供HttpSessionBindingListener和HttpSessionActivationListener监听器公用。首先我们看HttpSessionBindingListener监听器对应的代码,首先实现了HttpSessionBindingListener接口,同时继承了MyUser类,代码如下:

MyUserOfBinding监听器代码:

public class MyUserOfBinding extends MyUser implements HttpSessionBindingListener {

	private static final long serialVersionUID = 1L;

	@Override
	public void valueBound(HttpSessionBindingEvent event) {
		System.out.println("MyUserOfBinding-valueBound()方法,JavaBean对象绑定……");
	}

	@Override
	public void valueUnbound(HttpSessionBindingEvent event) {
		System.out.println("MyUserOfBinding-valueUnbound()方法,JavaBean对象解绑……");
	}
}
public class MyUser implements Serializable {
	
	private static final long serialVersionUID = 1L;

	private String uername;
	private String password;
	private String note;
	
	//getter.setter方法省略了
}

在IndexController.class测试类中添加如下方法:

@RequestMapping("/testSessionAttribute")
    public String testSessionAttribute(HttpServletRequest request, HttpServletResponse response){
		HttpSession session = request.getSession();
		System.out.println("########## 添加  ##############");
		session.setAttribute("username", "张三");
		session.setAttribute("age", 15);
		System.out.println("########### 移除  #############");
		session.removeAttribute("username");
		System.out.println("########## 替换  ##############");
		session.setAttribute("age", 16);
        return "SessionTest";
    }

  ListenerApplication类中@ServletComponentScan注解的包路径设置成:com.hsh.listener.session.bean,即只扫描该目录下的监听器配置(@WebListener注解的类),避免其他监听器干扰,其他和上面提到的ListenerApplication 代码一样,不再重复。

访问http://localhost:8080/servlet-listener/bindTest,控制台打印日志如下:
在这里插入图片描述

3.4、MyUserOfActivation监听器示例

  HttpSessionActivationListener监听器和HttpSessionBindingListener监听器一样,都是监听JavaBean对象的,不过HttpSessionActivationListener监听的测试,需要配合Tomcat服务器启动和关闭来进行测试。因为通过独立服务器部署的时候,Application类上的注解@ServletComponentScan就会失效,为了避免其他监听器干扰,建议注释这些监听器的@WebListener注解。需要使用的代码如下:

MyUserOfActivation代码如如下:

MyUser 类和前面的代码完全一样。

public class MyUserOfActivation extends MyUser implements HttpSessionActivationListener {

	private static final long serialVersionUID = 1L;

	@Override
	public void sessionWillPassivate(HttpSessionEvent se) {
		System.out.println("MyUserOfActivation-sessionWillPassivate()方法,JavaBean对象钝化……");
	}
	@Override
	public void sessionDidActivate(HttpSessionEvent se) {
		System.out.println("MyUserOfActivation-sessionDidActivate()方法,JavaBean对象激活……");
	}
}

在IndexController.class测试类中添加如下方法:

@RequestMapping("/activationTest")
    public String activationTest(HttpServletRequest request, HttpServletResponse response){
        HttpSession session = request.getSession();
        MyUserOfActivation user = new MyUserOfActivation();
        user.setUername("user1");
        session.setAttribute("user", user);
        
		return "SessionTest";
    }

  演示流程:首先需要使用独立的Tomcat部署应用,然后访问http://localhost:8080/servlet-listener/activationTest,设置信息到Session中,然后关闭Tomcat,这个时候会出现JavaBean对象被钝化的日志,然后再启动Tomcat,又会出现JavaBean被激活的日志,如下所示:

在这里插入图片描述
在这里插入图片描述

3.5、其他

  其他演示示例请参考Gitee,其中MyServletContextListener监听器,需要部署到独立的Tomcat上,通过启动和停止Tomcat来进行验证,其他的均可以通过url来进行。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68838.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!