真的了解Listener吗?- Listener详解

前言

学习JavaWeb, 肯定要学Javaweb3个组件:Servlet、Listener、Filter
前面了解了Servlet,接下来是Listener


目录

  1. Listener简介
  2. 监听器
  3. Listener原理
  4. 监听ServletContext域对象的创建和销毁
  5. 其他Listener
  6. 验证监听器
    6.1. HttpSessionBindingListener
    6.2. HttpSessionActivationListener
  7. 总结

Listener简介

Listener监听器大致是这样的:
在这里插入图片描述

Listener监听器有8种,它针对Web的三个域对象:HttpSession、ServletContext、ServletRequset,各有一个生命周期监听器和属性监听器
还有两个感知监听HttpSessionBindingListener(绑定与解绑)、HttpSessionActivationListener(钝化与活化)


监听器

监听器:实现了特定接口的一个Java程序,用于监听另一个Java程序的方法调用或者属性、状态改变,当监听到相应的事件时触发某种事件

有个问题,监听器是怎么监听的?
监听器怎么知道一个类发生了改变或者被调用??
只能让被监听的类告诉监听器,它被调用了或者是它被改变了

我们可以通过自己设计一个简单的监听器了解监听器的概念
一个PersonListener监听Person的动作:
监听器可以分为3个角色:监听器,被监听者,事件对象
当被监听者发生动作时,它会告诉监听者“我要动了”,并把事件对象(this)给监听者

被监听者Person.java

package com.company.Listen;

public class Person {
    private PersonListen personListen;
    private String name;

    public Person(PersonListen personListen,String name) {
        this.personListen = personListen;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void eat(){
    	//注册监听器,并传递事件对象
        personListen.doEat(new Event(this));
    }
    public void run(){
    	//注册监听器,并传递事件对象
        personListen.doRun(new Event(this));
    }
}


监听器PersonListener.java

package com.company.Listen;

public class PersonListen {
    public void doEat(Event event){
        System.out.println("监视到"+event.getSource().getName()+"正在eat");
    }
    public void doRun(Event event){
        System.out.println("监视到"+event.getSource().getName()+"正在run");
    }
}

事件对象Event:提供被监听者的信息

package com.company.Listen;

public class Event {
    private Person source;

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

    public Person getSource() {
        return source;
    }

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

PersonTest:

package com.company.Listen;

public class PersonTest {
    public static void main(String[] args) {
        Person person = new Person(new PersonListen(),"zhangsan");
        person.eat();
        person.run();
    }
}

可以看到,当person开始eat、run时,监听器监听到了动作,并触发监听器的方法
在这里插入图片描述

这是监听器模式的思想,也是JavaWeb中Listener的思想


Listener原理

前面了解了监听器模式,在去看Javaweb中的监听器,会发现清晰了许多

以ServletContextListener为例(3个域对象的Listener都差不多)
在这里插入图片描述
ServletContextListener是用来监听ServletContext的生命周期
他提供了两个空方法供我们自定义监听事件,并传入了ServletContextEvent对象

ServletContextEvent是什么呢?

他就是事件对象,封装了被监听者ServletContext
在这里插入图片描述

到这里就对Listener原理很清晰了,当然可以继续深入到ServletContext
但因为ServletContext是由服务器实现的,暂时没有这能力

Listener原理:被监听者会注册监听器,当有事件发生时,将事件对象封装传递给监听器,触发监听器对应的事件(程序员自定义)


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

实现ServletContextListener 接口,重写contextInitialized、contextDestroyed放过

package listen;

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

public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println(sce.getServletContext().getClass()+"被创建了。。。");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println(sce.getServletContext().getClass()+"被销毁了。。。");
    }
}

在web.xml上配置Listener

<listener>
    <listener-class>listen.MyServletContextListener</listener-class>
</listener>

来验证一下
运行Tomcat

在这里插入图片描述
当关闭Tomcat服务器时:

在这里插入图片描述

这个顺便验证了ServletContext的生命周期:服务器运行就会创建ServletContext,服务器关闭销毁ServletContext

ServletContext是由服务器创建:org.apache.catalina.core.ApplicationContextFacade


其他Listener

还是这张图,这就是JavaWeb内置的监听器
在这里插入图片描述

  • ServletContextListener、HttpSessionListener、ServletRequestListener都类似,都是监听该元素的生命周期:创建与销毁

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

  • ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener也是类似的

不监听生命周期,改成监听ServletContext对象中属性的增加、删除、替换
在这里插入图片描述

  • HttpSessionBindingListener是绑定与解绑,针对Session

我们前面学习Session时对Session的使用有了解
真的了解Session吗 - Session详解

Session类似与Map

绑定:setAttribute(String var1, Object var2),将元素保存(绑定)在Session
解绑:removeAttribute(String var1),通过name将元素从Session中移除(解绑)
在这里插入图片描述

  • HttpSessionActivationListener活化与钝化

也就是对Session序列化的感知

在这里插入图片描述


验证监听器

对元素的生命周期、属性变化的监听都类似
主要验证一下HttpSessionBindingListener和HttpSessionActivationListener

HttpSessionBindingListener

如果一个对象实现了HttpSessionBindingListener接口,当这个对象被绑定到Session中或者从session中被删除时,Servlet容器会通知这个对象,而这个对象在接收到通知后,可以做一些初始化或清除状态的操作

注意:是实现了该接口的对象绑定到Session

编写一个BindingListener类实现HttpSessionBindingListener 接口:

package listen;


import javax.servlet.http.*;

public class BindingListener implements HttpSessionBindingListener  {

    private String name;

    public BindingListener(String name) {
        this.name = name;
    }

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println(event.getName()+"-"+name+"加入了Session");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println(event.getName()+"-"+name+"被移出了Session");
    }
}

在SessionTest 中加入监听器对象

package Session;

import listen.BindingListener;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class SessionTest extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到Session
        HttpSession httpSession =  req.getSession();
        //存入数据
        httpSession.setAttribute("bindingListener",new BindingListener("zhangsan"));
    }
}

记得将SessionTest配置web.xml,监听器BindingListener在这仅作为一个存储数据,不需要配置web.xml

我们访问http://localhost:8080/sessionTest

在这里插入图片描述
监听到了Session中属性的绑定

关闭服务器(因为Session钝化了,而BindingListener对象没有实现序列化接口,即会被销毁):
在这里插入图片描述
当然,Session中的属性也被销毁了

HttpSessionBindingListener监听器与其他监听器不同,因为它绑定的是一个Session中的元素,所以它仅可以监听实现这个接口的元素是否绑定Session

注意:HttpSessionBindingEvent 对象有一些方法:
在这里插入图片描述

getSession可以得到当前对象绑定的Session
getName获得当前对象绑定的Session的name
getValue获得Session的vlaue

构造方法是给服务器用的

HttpSessionActivationListener

我们在Session中学习到,在服务器正常关闭的情况下,如果Session还存活,Session会钝化

那我们来验证一下HttpSessionActivationListener:
HttpSessionActivationListener和HttpSessionBindingListener一样,也是需要一个类实现这个接口,然后这个类作为属性存入Session中才可以监控Session的钝化与活化

创建一个Activation类继承HttpSessionActivationListener
并且要继承Serializable 使Activation对象能随着Session一起钝化

package listen;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;

public class Activation implements HttpSessionActivationListener, Serializable {
    String name;

    public Activation(String name) {
        this.name = name;
    }

    @Override
    public void sessionWillPassivate(HttpSessionEvent se) {
        System.out.println(se.getSession().getId()+" - "+name+"被钝化。。。");
    }

    @Override
    public void sessionDidActivate(HttpSessionEvent se) {
        System.out.println(se.getSession().getId()+" - "+name+"被活化。。。");
    }
}

在SessionTest里加上:

httpSession.setAttribute("ActuvationListener",new Activation("李四"));

我们知道如果服务器正常关闭,而Session保存的属性也是可以序列化的对象,对象会跟随Session一起序列化(钝化)

先刷新http://localhost:8080/sessionTest

在这里插入图片描述

再关闭服务器
在这里插入图片描述在这里插入图片描述

显示已经被钝化了

再启动:
Session钝化文件不见了
在这里插入图片描述
但是由于我们重启后在运行这个界面,会创建新的Session,原来的Session也就找不到了
我们写一个SessionTest1找到这个Session

package Session;

import listen.Activation;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

public class SessionTest1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        Activation activation = (Activation) session.getAttribute("ActuvationListener");
        String name = activation.getName();
        System.out.println(name);
        PrintWriter writer = resp.getWriter();
        writer.write(name);
    }
}

记得配置进web.xml
再演示一遍:
关闭服务器钝化:
在这里插入图片描述重启服务器:
运行SessionTest1

在这里插入图片描述

依旧找不到???
问题出在,我们每次在IDEA中关闭Tomcat都会删除Tomcat_9_0_22_JavaWeb目录,每次启动都会创建该目录,而Session钝化在其下肯定找不到

怎么改呢?

去自己的Tomcat目录下conf的context.xml文件中
在这里插入图片描述

在< Context>节点内加上

<Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true">
    <Store className="org.apache.catalina.session.FileStore" directory="D:\conf\Session"/>
</Manager>

directory是钝化文件放置的位置,自定义

再次重试:

在这里插入图片描述


总结

  1. Listener是监听器,有三个角色:监听器、被监听器、事件对象
  2. 被监听者会注册监听器,当有事件发生,将事件源(被监听者对象)封装成事件对象传递给监听器,监听器由程序员复制编写处理事件
  3. JavaWeb中有6+2种监听器,分别是监听3个域对象:ServletContext、HttpSession、ServletRequest的生命周期监听器与属性变化监听器和两个Session的绑定解绑、钝化活化监听器
  4. 前6中都类似,都有两个空方法由程序员编写:创建监听与销毁监听
  5. HttpSessionBindingListener、HttpSessionActivationListener两个与前6中监听器不同,这两种不需要在web.xml中配置,他们需要创建类实现这两个接口,然后将实现类加入Session,监听实现类的绑定与解绑,监听Session的钝化与活化
发布了109 篇原创文章 · 获赞 31 · 访问量 7372

猜你喜欢

转载自blog.csdn.net/key_768/article/details/105163071