2.10 Listener介绍

2.10 Listener介绍

Web应用在web容器中运行时,Web应用内部会不断地发生各种事件:
web应用被启动web应用被停止,用户session开始、用户session结束、用户请求到达等,通常来说,这些web事件对开发者是透明的。
实际上,Servlet API提供了大量监听器来监听Web应用的内部事件,从而允许当Web内部事件发生时回调事件监听器内的方法.

使用Listener步骤

使用Listener只需要两个步骤。

  1. 定义Listener实现类。
  2. 通过注解或在web.xml文件中配置Listerner

2.10.1 实现Listener类

AWT事件编程完全相似,监听不同web事件的监听器也不相同。常用的web事件监听器接口有如下几个。

监听器 描述
ServletContextListener 用于监听Web应用的启动和关闭
ServletContextAttributeListener 用于监听Servletcontext范围(application)内属性的改变。
ServletRequestListener 用于监听用户请求
ServletRequestAttributeListener 用于监听Servletrequest范围(request)内属性的改变。
HttpSessionListener 用于监听用户session的开始和结束
HttpSessionAttributeListener 用于监听Httpsession范围(session)内属性的改变。

下面先以ServletContextListener为例来介绍Listener的开发和使用,ServletContextListener用于监听Web应用的启动和关闭

ServletContextListener接口方法

Listener类必须实现ServletContextListener接口,该接口包含如下两个方法.

  • contextInitialized( ServletContextEvent sce):启动Web应用时,系统调用Listener的该方法。
  • contextDestroyed(ServletContextEvent sce):关闭Web应用时,系统调用Listener的该方法。

通过上面的介绍不难看出,ServletContextListener的作用有点类似于load-on-startup Servlet,都可用于在Web应用启动时,回调方法来启动某些后台程序,这些后台程序负责为系统运行提供支持。

GetConnListener.java

下面将创建一个获取数据库连接的Listener,该Listener会在应用启动时获取数据库连接,并将获取到的连接设置成application范围内的属性。
下面是该Listener的代码。

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package lee;

import java.sql.*;
import javax.servlet.*;
import javax.servlet.annotation.*;

@WebListener
public class GetConnListener implements ServletContextListener {
// 应该启动时,该方法被调用。
public void contextInitialized(ServletContextEvent sce) {
try {
// 取得该应用的ServletContext实例
ServletContext application = sce.getServletContext();
// 从配置参数中获取驱动
String driver = application.getInitParameter("driver");
// 从配置参数中获取数据库url
String url = application.getInitParameter("url");
// 从配置参数中获取用户名
String user = application.getInitParameter("user");
// 从配置参数中获取密码
String pass = application.getInitParameter("pass");
// 注册驱动
Class.forName(driver);
// 获取数据库连接
Connection conn = DriverManager.getConnection(url, user, pass);
// 将数据库连接设置成application范围内的属性
application.setAttribute("conn", conn);
} catch (Exception ex) {
System.out.println("Listener中获取数据库连接出现异常" + ex.getMessage());
}
}

// 应该关闭时,该方法被调用。
public void contextDestroyed(ServletContextEvent sce) {
// 取得该应用的ServletContext实例
ServletContext application = sce.getServletContext();
Connection conn = (Connection) application.getAttribute("conn");
// 关闭数据库连接
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}

上面的程序中重写了ServletContextListenercontextInitializedcontextDestroyed方法,这两个方法分别在应用启动、关闭时被触发。
上面ServletContextListener的两个方法分别实现获取数据库连接、关闭数据库连接的功能,这些功能都是为整个Web应用提供服务的。

程序中,contextInitialized()方法中代码:

1
2
3
4
5
6
7
8
9
ServletContext application = sce.getServletContext();
// 从配置参数中获取驱动
String driver = application.getInitParameter("driver");
// 从配置参数中获取数据库url
String url = application.getInitParameter("url");
// 从配置参数中获取用户名
String user = application.getInitParameter("user");
// 从配置参数中获取密码
String pass = application.getInitParameter("pass");

用于获取配置参数,细心的读者可能已经发现ServletContextListener获取的是web应用的配置参数,而不是像ServletFilter获取本身的配置参数。这是因为配置Listener时十分简单,只要简单地指定Listener实现类即可,不能配置初始化参数:

web.xml

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
<?xml version="1.0" encoding="GBK"?>
<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_3_1.xsd" version="3.1">
<!-- 配置第一个参数:driver -->
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
<!-- 配置第二个参数:url -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/javaee</param-value>
</context-param>
<!-- 配置第三个参数:user -->
<context-param>
<param-name>user</param-name>
<param-value>root</param-value>
</context-param>
<!-- 配置第四个参数:pass -->
<context-param>
<param-name>pass</param-name>
<param-value>32147</param-value>
</context-param>

<listener>
<!-- 指定Listener的实现类 -->
<listener-class>lee.GetConnListener</listener-class>
</listener>

</web-app>