1、Web监听器概述

监听器(Listener),主要用于监听某个事件是否发生。一旦该事件发生,便立即去处理监听器相应方法中的内容。

Java中给我们提供了许多监听器,我们这里介绍的是仅仅是Web应用中的**Web监听器**。

由于Web监听器均在javax.servlet包中定义,因此:Web监听器又称“Servlet监听器”。

  • **生命周期:**监听器在服务器启动时创建,监听器被移除或服务器关闭才会被销毁。

2、Web监听器种类

Servlet规范中定义了8个Web监听器接口,可用于监听ServletContextHttpSessionServletRequest对象的生命周期事件,以及这些对象的属性改变事件。

2.1、对象监听器

对象监听器主要用于监听对象的创建与销毁。用于监听对象的监听器有以下三种:

(1)ServletContext监听器: 用于监听ServletContext对象的创建与销毁。

监听器接口 监听事件
javax.servlet.ServletContextListener (1)当ServletContext对象创建时激活contextInitialized方法。(2)当ServletContext对象销毁时激活contextDestroyed方法。

(2)HttpSession监听器: 用于监听HttpSession对象的创建与销毁。

监听器接口 监听事件
javax.servlet.http.HttpSessionListener (1)当HttpSession对象创建时激活sessionCreated方法。(2)当HttpSession对象销毁时激活sessionDestroyed方法。

(3)ServletRequest监听器: 用于监听ServletRequest对象的创建与销毁。

监听器接口 监听事件
javax.servlet.ServletRequestListener (1)当ServletRequest对象创建时激活requestInitialized方法。(2)当ServletRequest对象销毁时激活requestDestroyed方法。

2.2、属性变化监听器

属性变化监听器主要用于监听属性的创建、修改和删除。用于监听属性变化的监听器有以下三种:

**(1)ServletContextAttributeListener监听器:**用于监听ServletContext中属性的创建、修改和删除。

监听器接口 监听事件
javax.servlet.ServletContextAttributeListener (1)当向ServletContext对象中添加属性时激活attributeAdded方法。(2)当ServletContext对象中的属性被修改时激活attributeReplaced方法。(3)当从ServletContext对象中删除属性时激活attributeRemoved方法。

**(2)HttpSessionAttributeListener监听器:**用于监听HttpSession中属性的创建、修改和删除。

监听器接口 监听事件
javax.servlet.http.HttpSessionAttributeListener (1)当向HttpSession对象中添加属性时激活attributeAdded方法。(2)当HttpSession对象中的属性被修改时激活attributeReplaced方法。(3)当从HttpSession对象中删除属性时激活attributeRemoved方法。

(2)HttpSessionAttributeListener监听器

**(3)ServletRequestAttributeListener监听器:**用于监听ServletRequest中属性的创建、修改和删除。

监听器接口 监听事件
javax.servlet.ServletRequestAttributeListener (1)当向ServletRequest对象中添加属性时激活attributeAdded方法。(2)当ServletRequest对象中的属性被修改时激活attributeReplaced方法。(3)当从ServletRequest对象中删除属性时激活attributeRemoved方法。

2.3、session状态监听器

**(1)HttpSessionBindingListener监听器:**用于监听某个(实体)类的对象在Session中的创建与删除。

监听器接口 监听事件
javax.servlet.http.HttpSessionBindingListener (1)当一个类的对象绑定到Session中时激活valueBound方法。(2)当一个类的对象从Session中删除时激活valueUnbound方法。

**(2)HttpSessionActivationListener监听器:**用于监听某个(实体)类的对象在Session中的钝化和活化。

监听器接口 监听事件
javax.servlet.http.HttpSessionActivationListener 如果一个类的对象绑定到Session中时,(1)当Session被钝化时激活sessionWillPassivate方法。(2)当Session被活化时激活sessionDidActivate方法。

**附:**由于Session中保存了大量访问网站相关的重要信息,过多的Session数据会占用过多的内存,导致服务器的性能下降。因此,类似于数据库对象的持久化,web容器也会把不常使用的Session数据持久化到本地文件中。

  • **钝化:**指的是把不用的Session数据序列化到本地文件中的过程。
  • **活化:**指的是从本地文件中读取Session数据的过程。

3、使用步骤

使用监听器与创建Servlet类似,主要分为以下两个步骤:

  • 编写一个Java类实现对应的Web监听器接口。
  • web.xml文件中配置(注册)监听器。

4、应用示例:统计网站在线人数

4.1、创建测试项目

(1)使用Maven模板创建一个MavenWeb项目(具体步骤参考《Maven详解》),项目名称为javaweb-listener

(2)同样地,填写项目名称和Maven项目GAV

(3)同样地,配置该MavenWeb项目的安装目录、配置文件和本地仓库。点击Finish按钮完成项目创建,等待Maven依赖包导入完毕。

(4)同样地,为了避免以后出现兼容性问题,建议我们先将该项目中的web.xml文件替换成“web-app_4_0”版本(具体步骤参考《Servlet详解》)。

(5)同样地,在该项目的main文件夹下新建一个java文件夹和一个resource文件夹,并将它们分别标记为“源码根目录”和“资源根目录”。

(6)同样地,配置Tomcat服务器,deploy(发布)javaweb-listener:war exploded包,并为该项目添加虚拟路径映射:/listener(具体步骤参考《Tomcat详解》)。

(7)在项目的pom.xml文件中添加项目依赖,并重新加载Maven项目。

pom.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>

(8)同样地,在该项目的java目录下新建一个com.atangbiji.servlet包,并在该包下新建一个OnlineCountServlet类,用于在服务器后台统计网站在线人数。同样地,让OnlineCountServlet类继承(extends)HttpServlet类,以实现Servlet接口。然后,在OnlineCountServlet类中重写doGetdoPost方法。

OnlineCountServlet.java文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class OnlineCountServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

ServletContext servletContext = req.getSession().getServletContext();
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");

System.out.println("========================");
System.out.println("网站当前在线人数为:" + onlineCount.intValue() + "人");
System.out.println("========================");
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp); //因为get和post只是不同的Http请求方式,所以它们之间可以相互调用。
}
}

(9)同样地,在该项目的Web配置文件(web.xml)中注册(映射)我们自己编写的Servlet,并为它提供一个浏览器可以访问的路径。

web.xml文件:

1
2
3
4
5
6
7
8
<servlet>
<servlet-name>onLineCountServlet</servlet-name>
<servlet-class>com.atangbiji.servlet.OnlineCountServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>onLineCountServlet</servlet-name>
<url-pattern>/count</url-pattern>
</servlet-mapping>

(10)为了测试Session对象的销毁,在该项目的Web配置文件(web.xml)中设置Session默认的失效时间为1min

web.xml文件:

1
2
3
4
5
<!-- 设置Session默认的失效时间 -->
<session-config>
<!-- 1分钟后Session自动失效,默认单位为分钟 -->
<session-timeout>1</session-timeout>
</session-config>

4.2、创建监听器,实现对应的Web监听器接口

(11)同样地,在该项目的java目录下新建一个com.atangbiji.listener包,并在该包下新建一个OnlineCountListener类,用于统计网站在线人数。类似地,让OnlineCountListener类实现(implements)javax.servlet.http中的HttpSessionListener接口。然后,在OnlineCountListener类中重写sessionCreatedsessionDestroyed方法。

OnlineCountListener.java文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//统计网站在线人数,即:统计Session
public class OnlineCountListener implements HttpSessionListener {
//当HttpSession对象创建时激活sessionCreated方法
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();//获取应用上下文
Integer onlineCount = (Integer)servletContext.getAttribute("OnlineCount");//获取应用上下文中的在线人数

if (onlineCount == null){
onlineCount = new Integer(1);
}else {
onlineCount = new Integer(onlineCount.intValue() + 1);
}
servletContext.setAttribute("OnlineCount",onlineCount);
System.out.println("新建Session的SessionID为:" + se.getSession().getId());
}

//当HttpSession对象销毁时激活sessionDestroyed方法
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();//获取应用上下文
Integer onlineCount = (Integer)servletContext.getAttribute("OnlineCount");//获取应用上下文中的在线人数

if (onlineCount == null){
onlineCount = new Integer(0);
}else {
onlineCount = new Integer(onlineCount.intValue() - 1);
}
servletContext.setAttribute("OnlineCount",onlineCount);
System.out.println("SessionID为:" + se.getSession().getId() + "的Session已经被删除!");
}
}

4.3、配置(注册)监听器

(12)类似地,在该项目的Web配置文件(web.xml)中注册(映射)我们自己编写的Listener

web.xml文件:

1
2
3
<listener>
<listener-class>com.atangbiji.listener.OnlineCountListener</listener-class>
</listener>

4.4、测试结果

(13)重启Tomcat。若在谷歌浏览器中输入http://localhost:8080/listener/count,则网站当前在线人数为2人。此时,服务器后台输出结果如下图所示:

测试结果1

**注:**由于JSP的默认指令<%@ page session="true"%>,导致Tomcat启动后默认访问JSP首面时,会自动创建一个Session。我们可以在JSP页面顶部置通过如下代码将其关闭。

1
<%@ page session="false"%>

(14)在不关闭谷歌浏览器的情况下,再在火狐浏览器中输入http://localhost:8080/listener/count,则网站当前在线人数变为3人。此时,服务器后台输出结果如下图所示:

测试结果2

(15)1min后,3个Session对象均自动销毁。此时,在不关闭谷歌浏览器和火狐浏览器的情况下,再在谷歌浏览器中刷新http://localhost:8080/listener/count页面,则网站当前在线人数变为1人。此时,服务器后台输出结果如下图所示:

测试结果3

**注:**当一个Session被注销后,若通过该浏览器重新访问该网站,则服务器会立即重新创建一个新的Session

(本讲完,系列博文持续更新中…… )

阿汤笔迹微信公众平台

关注**“阿汤笔迹”** 微信公众号,获取更多学习笔记。
原文地址:http://www.atangbiji.com/2022/10/23/listener
博主最新文章在个人博客 http://www.atangbiji.com/ 发布。