Listener监听器

https://www.cnblogs.com/xdp-gacl/p/3961929.html

一、监听器介绍

1.1 监听器的概念

image.png

监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。监听器其实就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行。

1.2 监听的内容

监听器对象:监听的对象。
注册(绑定):将"监听器"对象注册给"事件源". 当事件源发生某些行为,监听对象将被执行。
事件:事件源行为的称呼。

2、javaweb的监听器

​ javaweb的监听器:监听ServletContext,HttpSession,ServletRequest三个域对象状态

​ 事件源和监听器绑定的过程:通过配置web.xml完成

2.1 Servlet中提供了8个监听器

一类:监听三个域对象的创建和销毁的监听器

对象类型 对应的监听器
ServletContext ServletContextListener
HttpSession HttpSessionListener
HttpServletRequest ServletRequestListener

二类:监听三个域对象的属性变更的监听器.(属性添加,属性移除,属性替换)

对象类型 对应的监听器
ServletContext ServletContextAttributeListener
HttpSession HttpSessionAttributeListener
HttpServletRequest ServletRequestAttributeListener

三类:监听HttpSession对象中的JavaBean的状态的改变.(绑定,解除绑定,钝化和活化)2个

对象类型 对应的监听器
HttpSession HttpSessionActivationListener(钝化和活化)
HttpSession HttpSessionBindingListener(绑定,解除绑定)

注意:HttpSessionActivationListener不需要web.xml配置文件

现了HttpSessionActivationListener接口的 JavaBean 对象可以感知自己被活化和钝化的事件
活化:javabean对象和Session一起被反序列化(活化)到内存中(硬盘到内存);
钝化:javabean对象和Session一起序列化到硬盘中(内存到硬盘);
javabean对象存在Session中,当服务器把session序列化到硬盘上时,如果Session中的javabean对象实现了Serializable接口
那么服务器会把session中的javabean对象一起序列化到硬盘上,javabean对象和Session一起被序列化到硬盘中的这个操作称之为钝化
如果Session中的javabean对象没有实现Serializable接口,那么服务器会先把Session中没有实现Serializable接口的javabean对象移除
然后再把Session序列化(钝化)到硬盘中;

当绑定到 HttpSession对象中的javabean对象将要随 HttpSession对象被钝化之前,
web服务器调用该javabean对象的 sessionWillPassivate方法,
这样javabean对象就可以知道自己将要和 HttpSession对象一起被序列化(钝化)到硬盘中
当绑定到HttpSession对象中的javabean对象将要随 HttpSession对象被活化之后,
web服务器调用该javabean对象的sessionDidActive方法,
这样javabean对象就可以知道自己将要和 HttpSession对象一起被反序列化(活化)回到内存中 

HttpSessionBindingListener监听器:感知Session绑定的事件监听器
注意:HttpSessionBindingListener不需要web.xml配置文件

保存在Session域中的对象可以有多种状态:
(1)绑定(session.setAttribute("bean",Object))到Session中;
(2)从Session域中解除(session.removeAttribute("bean"))绑定;
(3)随Session对象持久化到一个存储设备中;
(4)随Session对象从一个存储设备中恢复;
Servlet 规范中定义了两个特殊的监听器接口"HttpSessionBindingListener和HttpSessionActivationListener"来帮助JavaBean 对象了解自己在Session域中的这些状态。

2.2 一类监听器:监听三个域对象的创建和销毁的监听器

ServletContext对象何时创建和销毁:

创建:服务器启动时候,服务器可以为每个WEB应用创建一个单独的ServletContext.
销毁:服务器关闭的时候,或者项目从服务器中移除.

HttpSessionListener对象何时创建和销毁:

创建:服务器第一次访问Servlet时,调用getSession()方法的时候. 如果访问的是jsp则直接创建。
销毁:session过期了(默认30分钟)
        session.invalidate()手动销毁  
              非正常关闭服务器(正常关闭序列化到硬盘)!

ServletRequestListener对象何时创建和销毁:

创建:客户端向服务器发送请求的时候
销毁:服务器为这次请求作出了响应时候

三、监听器案例

3.1 监听window窗口的事件监听器

package me.gacl.listener.demo;
import java.awt.Frame;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Demo1 {
    /**
     *java的事件监听机制
     *1、事件监听涉及到三个组件:事件源、事件对象、事件监听器
     *2、当事件源上发生某一个动作时,它会调用事件监听器的一个方法,并在调用该方法时把事件对象传递进去,
     *    开发人员在监听器中通过事件对象,就可以拿到事件源,从而对事件源进行操作。
     */
    public static void main(String[] args) {
        Frame f = new Frame();
        f.setSize(400, 400);
        f.setVisible(true);
        //注册事件监听器
        f.addWindowListener(new WindowListener(){
            public void windowActivated(WindowEvent e) {
                
            }
            public void windowClosed(WindowEvent e) {
                
            }
            /**
             * 当window窗体关闭时就会WindowListener这个监听器监听到,
             * 监听器就会调用windowClosing方法处理window窗体关闭时的动作
             */
            public void windowClosing(WindowEvent e) {
                //通过事件对象e来获取事件源对象
                Frame f = (Frame) e.getSource();
                System.out.println(f+"窗体正在关闭");
                f.dispose();
            }
            public void windowDeactivated(WindowEvent e) {
                
            }
            public void windowDeiconified(WindowEvent e) {
                
            }
            public void windowIconified(WindowEvent e) {
                
            }
            public void windowOpened(WindowEvent e) {
                
            }
        });
    }
}

3.2 设计一个可以被别的对象监听的对象

我们平时做开发的时候,我们是写监听器去监听其他对象,那么我们如果想设计一个对象,让这个对象可以被别的对象监听又该怎么做呢,可以按照严格的事件处理模型来设计一个对象,这个对象就可以被别的对象监听,事件处理模型涉及到三个组件:事件源、事件对象、事件监听器。

package me.gacl.observer;

/**
* @ClassName: Person(事件源)
* @Description: 设计一个Person类作为事件源,这个类的对象的行为(比如吃饭、跑步)可以被其他的对象监听
* @author: 孤傲苍狼
* @date: 2014-9-9 下午9:26:06
*
*/  
public class Person {
    /**
    * @Field: listener
    *          在Person类中定义一个PersonListener变量来记住传递进来的监听器
    */ 
    private PersonListener listener;

    /**
    * @Method: eat
    * @Description: 设计Person的行为:吃
    * @Anthor:孤傲苍狼
    *
    */ 
    public void eat() {
        if (listener != null) {
            /**
             * 调用监听器的doeat方法监听Person类对象eat(吃)这个动作,将事件对象Event传递给doeat方法,
             * 事件对象封装了事件源,new Event(this)中的this代表的就是事件源
             */
            listener.doeat(new Event(this));
        }
    }

    /**
    * @Method: run
    * @Description: 设计Person的行为:跑
    * @Anthor:孤傲苍狼
    *
    */ 
    public void run() {
        if (listener != null) {
            /**
             * 调用监听器的dorun方法监听Person类对象run(跑)这个动作,将事件对象Event传递给doeat方法,
             * 事件对象封装了事件源,new Event(this)中的this代表的就是事件源
             */
            listener.dorun(new Event(this));
        }
    }

    /**
    * @Method: registerListener
    * @Description: 这个方法是用来注册对Person类对象的行为进行监听的监听器
    * @Anthor:孤傲苍狼
    *
    * @param listener
    */ 
    public void registerListener(PersonListener listener) {
        this.listener = listener;
    }
}

/**
* @ClassName: PersonListener(事件监听器)
* @Description: 设计Person类(事件源)的监听器接口
* @author: 孤傲苍狼
* @date: 2014-9-9 下午9:28:06
*
*/ 
interface PersonListener {

    /**
    * @Method: doeat
    * @Description: 这个方法是用来监听Person对象eat(吃)这个行为动作,
    *                 当实现类实现doeat方法时就可以监听到Person类对象eat(吃)这个动作
    * @Anthor:孤傲苍狼
    *
    * @param e
    */ 
    void doeat(Event e);

    /**
    * @Method: dorun
    * @Description: 这个方法是用来监听Person对象run(跑)这个行为动作,
    *                 当实现类实现dorun方法时就可以监听到Person类对象run(跑)这个动作
    * @Anthor:孤傲苍狼
    *
    * @param e
    */ 
    void dorun(Event e);

}

/**
* @ClassName: Event(事件对象)
* @Description:设计事件类,用来封装事件源
* @author: 孤傲苍狼
* @date: 2014-9-9 下午9:37:56
*
*/ 
class Event {

    /**
    * @Field: source
    *          事件源(Person就是事件源)
    */ 
    private Person source;

    public Event() {
        
    }

    public Event(Person source) {
        this.source = source;
    }

    public Person getSource() {
        return source;
    }

    public void setSource(Person source) {
        this.source = source;
    }
}

四、JavaWeb中的监听器

4.1 基本概念

JavaWeb中的监听器是Servlet规范中定义的一种特殊类,它用于监听web应用程序中的ServletContext, HttpSession和 ServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。

4.2 Servlet监听器的分类

在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext,HttpSession和ServletRequest这三个域对象
  Servlet规范针对这三个对象上的操作,又把多种类型的监听器划分为三种类型:
1、监听域对象自身的创建和销毁的事件监听器。
2、监听域对象中的属性的增加和删除的事件监听器。
3、监听绑定到HttpSession域中的某个对象的状态的事件监听器。

4.3 监听ServletContext域对象的创建和销毁

ServletContextListener接口用于监听ServletContext对象的创建和销毁事件。实现了ServletContextListener接口的类都可以对ServletContext对象的创建和销毁进行监听。

当ServletContext对象被创建时,激发contextInitialized (ServletContextEvent sce)方法。

当ServletContext对象被销毁时,激发contextDestroyed(ServletContextEvent sce)方法。
ServletContext域对象创建和销毁时机:

  • 创建:服务器启动针对每一个Web应用创建ServletContext
  • 销毁:服务器关闭前先关闭代表每一个web应用的- ServletContext

1、编写监听器。

package me.gacl.web.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
* @ClassName: MyServletContextListener
* @Description: MyServletContextListener类实现了ServletContextListener接口,
*                 因此可以对ServletContext对象的创建和销毁这两个动作进行监听。
* @author: 孤傲苍狼
* @date: 2014-9-9 下午10:26:16
*
*/ 
public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext对象创建");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext对象销毁");
    }
}

2、在web.xml文件中注册监听器
我们在上面的中讲到,要想监听事件源,那么必须将监听器注册到事件源上才能够实现对事件源的行为动作进行监听,在JavaWeb中,监听的注册是在web.xml文件中进行配置的,

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>    
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <!-- 注册针对ServletContext对象进行监听的监听器 -->
  <listener>
      <description>ServletContextListener监听器</description>
      <!--实现了ServletContextListener接口的监听器类 -->
      <listener-class>me.gacl.web.listener.MyServletContextListener</listener-class>
  </listener>
</web-app>

经过这两个步骤,我们就完成了监听器的编写和注册,Web服务器在启动时,就会自动把在web.xml中配置的监听器注册到ServletContext对象上,这样开发好的MyServletContextListener监听器就可以对ServletContext对象进行监听了。
Person===>ServletContext
Event===>ServletContextEvent
PersonListener===>ServletContextListener

4.4 监听HttpSession域对象的创建和销毁

HttpSessionListener 接口用于监听HttpSession对象的创建和销毁
创建一个Session时,激发sessionCreated (HttpSessionEvent se) 方法
销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se) 方法。
范例:编写一个MyHttpSessionListener类,实现HttpSessionListener接口,监听HttpSession对象的创建和销毁
1、编写监听器

package me.gacl.web.listener;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
* @ClassName: MyHttpSessionListener
* @Description: MyHttpSessionListener类实现了HttpSessionListener接口,
*                 因此可以对HttpSession对象的创建和销毁这两个动作进行监听。
* @author: 孤傲苍狼
* @date: 2014-9-9 下午11:04:33
*
*/ 
public class MyHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println( se.getSession() + "创建了!!");
    }

    /* HttpSession的销毁时机需要在web.xml中进行配置,如下:
     * <session-config>
              <session-timeout>1</session-timeout>
          </session-config>
          这样配置就表示session在1分钟之后就被销毁
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("session销毁了!!");
    }
}

2、在web.xml文件中注册监听器

<!--注册针对HttpSession对象进行监听的监听器-->
   <listener>
      <description>HttpSessionListener监听器</description>
      <listener-class>me.gacl.web.listener.MyHttpSessionListener</listener-class>
  </listener>
  <!-- 配置HttpSession对象的销毁时机 -->
  <session-config>
      <!--配置HttpSession对象的1分钟之后销毁 -->
      <session-timeout>1</session-timeout>
  </session-config>

当我们访问jsp页面时,HttpSession对象就会创建,此时就可以在HttpSessionListener观察到HttpSession对象的创建过程了,我们可以写一个jsp页面观察HttpSession对象创建的过程。

4.5 监听ServletRequest域对象的创建和销毁

ServletRequestListener接口用于监听ServletRequest 对象的创建和销毁

Request对象被创建时,监听器的requestInitialized(ServletRequestEvent sre)方法将会被调用
Request对象被销毁时,监听器的
requestDestroyed(ServletRequestEvent sre)方法将会被调用

ServletRequest域对象创建和销毁时机:

  • 创建:用户每一次访问都会创建request对象
  • 销毁:当前访问结束,request对象就会销毁

范例:编写一个MyServletRequestListener类,实现ServletRequestListener接口,监听ServletRequest对象的创建和销毁
1、编写监听器

package me.gacl.web.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

/**
* @ClassName: MyServletRequestListener
* @Description: MyServletRequestListener类实现了ServletRequestListener接口,
*                 因此可以对ServletRequest对象的创建和销毁这两个动作进行监听。
* @author: 孤傲苍狼
* @date: 2014-9-9 下午11:50:08
*
*/ 
public class MyServletRequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println(sre.getServletRequest() + "销毁了!!");
        
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println(sre.getServletRequest() + "创建了!!");
    }
}

在web.xml文件中注册监听器

<!--注册针对ServletRequest对象进行监听的监听器-->
<listener>
    <description>ServletRequestListener监听器</description>
    <listener-class>me.gacl.web.listener.MyServletRequestListener</listener-class>
</listener>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容