Java监听器详解

一.监听器的定义

是指专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生变化时,立即采取相应的行动。

Web应用当中监听器是什么?

在这里插入图片描述
web监听器由servlet规范提供的,它可以监听客户端的请求,服务端的操作,监听的对象包括ServletContext,HttpSession,ServletRequest三个预对象(内置对象),分别对应aplication,session,request。
在这里插入图片描述

内置对象

JSP中一共预先定义了9个这样的内置对象,分别为:request、response、session、application、out、pagecontext、config、page、exception
内置对象(又叫隐含对象)特点:

  1. 由JSP规范提供,不用编写者实例化。
  2. 通过Web容器实现和管理
  3. 所有JSP页面均可使用
  4. 只有在脚本元素的表达式或代码段中才可使用(<%=使用内置对象%>或<%使用内置对象%>)
request对象

request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。

session对象

session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型。

application对象

application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。

Web监听器概念

Servlet规范中定义的一种特殊类
用于监听ServletContext,HttpSession和ServletRequest等域对象的创建与销毁事件用于监听域对象的属性发生修改的事件可以在事件发生前,发生后做一些必要的处理

二.Web监听器的用途

1.统计在线人数和在线用户
2.系统启动时加载初始化信息
3.统计网站访问量
4.跟Spring结合

三.第一个Web监听器

实现步骤

1.创建一个实现监听器接口的类

在这里插入图片描述
在这里插入图片描述
代码如下:

package com.java.listener;

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

/**
 * @author : xiayj
 * @date : 2019/8/3 17:58
 */
public class FirstListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}
2.配置web.xml进行注册

把监听对象放到web.xml中

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <listener>
        <listener-class>com.java.listener.FirstListener</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>
</web-app>

启动tomcat,控制台输出如下说明当web应用启动时会自动创建一个application对象,且只有一个
在这里插入图片描述
关闭tomcat,如下表示当前应用销毁
在这里插入图片描述

监听器的启动顺序

在这里插入图片描述

四.监听器的分类

1.按监听的对象划分

1)用于监听应用程序环境对象(ServletContext)的事件监听器
2)用于监听用户会话对象(HttpSession)的事件监听器
3)用于监听请求消息对象(ServletRequest)的事件监听器

2.按监听的事件划分

1)监听域对象自身的创建和销毁的事件监听器

在这里插入图片描述

ServletContext的创建与销毁

ServletContext实现了ServletContextListener用于监听它的创建与销毁事件,一个web项目可以定义多个ServletContextListener,但一个web项目只有一个ServletContext对象。
ServletContextListener有两个事件处理方法,这两个方法都会传入ServletContextEvent事件对象,可以获取ServletContext对象以及一些初始化参数。ServletContextListener主要用途:可以做定时器,加载全局属性对象,创建全局的数据库连接,加载一些缓存信息。
在这里插入图片描述
web.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <listener>
        <listener-class>com.java.listener.FirstListener</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>
<!--配置初始化参数-->
    <context-param>
        <param-name>initParam</param-name>
        <param-value>listener</param-value>
    </context-param>
</web-app>

代码实现:

package com.java.listener;

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

/**
 * @author : xiayj
 * @date : 2019/8/3 17:58
 */
public class FirstListener implements ServletContextListener {
    //ServletContext是上下文对象,当web应用启动时创建,web应用销毁时销毁
    @Override
    public void contextInitialized(ServletContextEvent sce) {
//项目启动时获取初始化参数
        String initParam = sce.getServletContext().getInitParameter("initParam");
        System.out.println("contextInitialized : initParam = " + initParam);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
//销毁主要用于当数据库连接关闭时释放一些不必要的资源
        System.out.println("contextDestroyed");
    }
}

项目启动结果如下,说明当项目启动时就加载了在web.xml中配置的参数
在这里插入图片描述

HttpSession的创建与销毁

与ServletContext类似,HttpSession实现了HttpSessionListener用于监听它的创建与销毁事件,一个web项目可以定义多个HttpSessionListener,但一个web项目只有一个HttpSession对象。HttpSessionEvent事件对象,可以获取当前被创建的HttpSession对象。HttpSessionListener主要用途:统计在线人数,记录访问日志。
在这里插入图片描述
Session创建:用户打开浏览器第一次访问我们应用时,这次会话web容器会分配一个session,可以在session中保存一些信息
Session销毁:1.手动点退出,关闭服务器2.关闭浏览器一段时间直到session过期3.不关闭浏览器,session超时
实现HttpSessionListener:

package com.java.listener;

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

/**
 * @author : xiayj
 * @date : 2019/8/4 16:59
 */
public class MyHttpSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("sessionCreated");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("sessionDestroyed");
    }
}

web.xml文件加如下配置

<!--配置session超时时间,1表示1分钟0表示没有超时限制-->
<session-config>
    <session-timeout>1</session-timeout>
</session-config>

访问项目
在这里插入图片描述
控制台输出如下Listener监听到session创建
在这里插入图片描述
等一分钟后,监听到session被销毁
在这里插入图片描述

ServletRequest的创建与销毁

ServletRequest实现了ServletRequestListener用于监听它的创建与销毁事件,一个web项目可以定义多个ServletRequestListener,但一个web项目只有一个ServletRequest对象。ServletRequestListener主要用途:读取request里的参数,记录访问历史,路径。
在这里插入图片描述
实现ServletRequestListener

package com.java.listener;

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

/**
 * @author : xiayj
 * @date : 2019/8/4 17:54
 */
public class MyServletRequestListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        //获取当前的请求参数
        String name = sre.getServletRequest().getParameter("name");
        System.out.println("requestInitialized");
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("requestDestroyed");
    }
}

Web.xml中增加监听器配置信息

<listener>
    <listener-class>com.java.listener.MyServletRequestListener</listener-class>
</listener>

启动项目,打开浏览器,查看控制台如下,可知request监听到了用户的访问请求,并在请求结束后销毁
在这里插入图片描述

2)监听域对象中的属性的增加和删除的事件监听器

在这里插入图片描述
代码实现:
新建三个类

package com.java.listener;

import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;

/**
 * @author : xiayj
 * @date : 2019/8/10 17:18
 */
public class MyServletRequestAttributeListener implements ServletRequestAttributeListener {
    @Override
    public void attributeAdded(ServletRequestAttributeEvent srae) {
//可知是什么对象添加了什么属性,移除了什么属性       System.out.println("ServletRequest_attributeAdded:"+srae.getName());
    }

    @Override
    public void attributeRemoved(ServletRequestAttributeEvent srae) {
        System.out.println("ServletRequest_attributeRemoved:"+srae.getName());
    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent srae) {
        System.out.println("ServletRequest_attributeReplaced:"+srae.getName());
    }
}
package com.java.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

/**
 * @author : xiayj
 * @date : 2019/8/10 16:55
 */
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {
    @Override
    public void attributeAdded(HttpSessionBindingEvent se) {
        System.out.println("HttpSession_attributeAdded:"+se.getName());
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent se) {
        System.out.println("HttpSession_attributeRemoved:"+se.getName());
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent se) {
        System.out.println("HttpSession_attributeReplaced:"+se.getName());
    }
}
package com.java.listener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;

/**
 * @author : xiayj
 * @date : 2019/8/10 16:52
 */
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext_attributeAdded:"+scae.getName());
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext_attributeRemoved:"+scae.getName());
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent scae) {
        System.out.println("ServletContext_attributeReplaced:"+scae.getName());
    }
}

Web.xml文件中注册监听器

<listener>
    <listener-class>com.java.listener.MyHttpSessionAttributeListener</listener-class>
</listener>
<listener>
    <listener-class>com.java.listener.MyServletContextAttributeListener</listener-class>
</listener>
<listener>
    <listener-class>com.java.listener.MyServletRequestAttributeListener</listener-class>
</listener>

创建新增各个属性值得jsp界面,为了方便在每个页面都加上了初始化,销毁的按钮
index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>这是myweb应用</title>
  </head>
  <body>
  你好!这是一个listener
  <button onclick="location.href='<%=request.getContextPath()%>/init.jsp';">Init</button>
  <button onclick="location.href='<%=request.getContextPath()%>/destory.jsp';">Destory</button>
  </body>
</html>

init.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServletPath();
//添加属性,让Listener监听执行attributeAdded方法
request.setAttribute("requestName","requestValue");
request.getSession().setAttribute("sessionName","sessionValue");
request.getSession().getServletContext().setAttribute("contextName","contextValue");
%>
<html>
<head>
    <title>Title</title>
</head>
<body>
这是初始化值得界面
<button onclick="location.href='<%=request.getContextPath()%>/init.jsp';">Init</button>
<button onclick="location.href='<%=request.getContextPath()%>/destory.jsp';">Destory</button>
</body>
</html>

destory.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServletPath();
    //移除属性,让Listener监听执行attributeRemoved方法
    request.removeAttribute("requestName");
    request.getSession().removeAttribute("sessionName");
    request.getSession().getServletContext().removeAttribute("contextName");
%>
<html>
<head>
    <title>Title</title>
</head>
<body>
这是销毁界面
<button onclick="location.href='<%=request.getContextPath()%>/init.jsp';">Init</button>
<button onclick="location.href='<%=request.getContextPath()%>/destory.jsp';">Destory</button>
</body>
</html>

超时时间改为0

<!--配置session超时时间,1表示1分钟0表示没有超时限制-->
<session-config>
    <session-timeout>0</session-timeout>
</session-config>

打开主页面
在这里插入图片描述
点击init,控制台输出如下
在这里插入图片描述
再次点击init
在这里插入图片描述
点击destory,属性被移除,request对象因为已经被销毁了,域中已没有requestName属性,所以没有移除信息
在这里插入图片描述

3)监听绑定到HttpSession域中的某个对象的状态的事件监听器

在这里插入图片描述
绑定:通过getSession().setAttribute将对象保存到session对象中
解除绑定:通过getSession().removeAttribute将对象从session对象中移除
钝化:将session对象持久化到存储设备上
活化:将session对象从存储设备上恢复

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码实现:
新建user类

package com.java.entity;

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

/**
 * @author : xiayj
 * @date : 2019/8/17 16:09
 */
/** 想要钝化或活化必须实现Serializable接口*/
public class User implements HttpSessionBindingListener, HttpSessionActivationListener, Serializable {
    private String username;
    private String password;
    /** 对象绑定执行*/
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("valueBound Name:"+event.getName());
    }
    /** 对象解除绑定执行*/
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("valueUnbound Name:"+event.getName());
    }
    /** 钝化*/
    @Override
    public void sessionWillPassivate(HttpSessionEvent se) {
        System.out.println("sessionWillPassivate"+se.getSource());
    }
    /** 活化*/
    @Override
    public void sessionDidActivate(HttpSessionEvent se) {
        System.out.println("sessionDidActivate"+se.getSource());
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
绑定/解除绑定测试:

在init文件里增加如下:

//将用户实例放到session中
request.getSession().setAttribute("currentUser",new com.java.entity.User());

在destory文件里增加如下:

request.getSession().removeAttribute("currentUser");

启动项目,打开首页:
在这里插入图片描述
点击init和destory,控制台分别输出如下,表明当对象实现HttpSessionBindingListener接口后,只要对象被session绑定,就会触发事件,执行valueBound方法,当解除绑定后,执行valueUnBound方法
在这里插入图片描述
在这里插入图片描述

钝化/活化测试

启动tomcat,打开项目,可以看到控制台已经创建session
在这里插入图片描述
点击init,可以看到session中保存了几个属性值
在这里插入图片描述
关闭tomcat,控制输出如下,sessionWillPassivateorg.apache.catalina.session.StandardSessionFacade@1e7c7811 就是session钝化的输出,StandardSession是默认的钝化管理器
在这里插入图片描述
钝化的文件保存位置如下
在这里插入图片描述
在首页新增如下:

<!-- 在首页获取用户对象 正常情况下因为tomcat已关闭,session中用户对象应该已被销毁,
但因为实现了HttpSessionActivationListener接口,tomcat重新启动时会活化保存的session文件-->
<%=request.getSession().getAttribute("currentUser")%>
你好!这是一个listener
<button onclick="location.href='<%=request.getContextPath()%>/init.jsp';">Init</button>
<button onclick="location.href='<%=request.getContextPath()%>/destory.jsp';">Destory</button>

重启tomcat,控制台输出如下:
在这里插入图片描述
打开首页,可以看到之前钝化的user对象被输出
在这里插入图片描述
Ps:如果出现可以活化,但是无法钝化的问题即重启tomcat没有调用 sessionDidActivate()方法,浏览器端也获取不到重启前存入的对象
这是因为每次重启tomcat会将如下目录删除并重新生成,之前钝化的session文件也会被一起删除
在这里插入图片描述
解决方法:在tomcat安装目录下conf/context.xml配置文件里增加如下配置,directory里是自定义的session文件存储路径

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

在Servlet3.0版本以上提供@WebListener注解将一个实现了特定监听器接口(比如ServletContextListener,HttpSessionListener)的类定义为监听器,这样在web应用中使用监听器时不需要在web.xml文件中配置监听器的相关描述信息,感兴趣的可以自己去研究一下,用法差不多。

参考文章:Jsp:九大内置对象https://my.oschina.net/u/3805464/blog/1813805
本文章内容是对慕课网课程内容的一个总结,感兴趣的同学可以去慕课网学习该课程
地址如下:https://www.imooc.com/learn/271

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章