监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。
监听器其实就是一个实现特定接口的普通Java程序,这个程序专门用于监听另一个Java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行。Java中的事件监听机制可用下图来表示:
package cn.liayun.demo;
import java.awt.Frame;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Demo1 {
public static void main(String[] args) {
Frame f = new Frame();//代表一个window窗口
f.setSize(400, 400);
f.setVisible(true);
//把监听器注册到事件源上
f.addWindowListener(new MyListener());
}
}
//编写一个监听器
class MyListener implements WindowListener {
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
/*
* 当window窗体关闭时,MyListener这个监听器就会监听到,
* 监听器就会调用windowClosing方法处理window窗体关闭时的动作
*/
@Override
public void windowClosing(WindowEvent e) {
Frame f = (Frame) e.getSource();//拿到事件源
f.dispose();//关闭窗体
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
//window窗口从正常状态变为最小化状态时调用
@Override
public void windowIconified(WindowEvent e) {
System.out.println("窗口最小化了!");
}
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
}
我们平时做开发的时候,我们是写监听器去监听其他对象,那么我们如果想设计一个对象,让这个对象可以被别的对象监听又该怎么做呢?这时我们可以使用观察者设计模式按照严格的事件处理模型来设计一个对象,这个对象就可以被别的对象监听了,事件处理模型涉及到三个组件:事件源、事件对象和事件监听器。
我们一开始可能会简单地设计这样一个Person对象:
这时,如果Person对象想要被别人监听,那么该Person对象就要允许别人往你这个对象上注册一个监听器。假设人家注册了一个监听器进来,那么该监听器由谁调用呢?监听器由事件源调用,事件源上发生动作,它调用监听器的方法。也就是说别人调用Person对象的一个方法注册一个监听器,等会儿Person对象就要调用监听器的方法,也即Person对象现在写的程序要调用别人将来写的程序,那么它就要对外暴露一个接口。
对外暴露一个接口,别人实现这个接口,Person对象针对这个接口进行调用,那么这个接口里定义几个方法呢?Person这个对象身上有2个动作想被别人监听,所以这个接口应针对这2个动作定义2个相对应的方法。此时,Person对象的具体代码应为:
但这样设计出来的东西少了什么呢?事件处理涉及到3个组件,而现在只涉及到2个组件,一个事件源和一个事件监听器,少了事件对象。事件对象在事件监听机制里面主要是用于封装事件源的。也就是说在调用事件源的run()方法时,就会调用监听器的dorun()方法,在调用该方法时,应该传一个事件对象过去,通过这个事件对象,把到底是哪个事件源上发生的操作传过去。此时,我们按照事件处理模型设计的Person对象的完整代码如下所示:
经过这样的设计之后,Person类的对象就可以被其他对象监听了。测试代码如下:
运行结果如下:
JavaWeb中的监听器是Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession和ServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext,HttpSession和ServletRequest这三个域对象。Servlet规范针对这三个对象上的操作,又把多种类型的监听器划分为三种类型:
ServletContextListener接口用于监听ServletContext对象的创建和销毁事件。实现了ServletContextListener接口的类都可以对ServletContext对象的创建和销毁进行监听。
那么会有一个问题:ServletContext域对象何时创建和销毁呢?
案例:编写一个MyServletContextListener类,实现ServletContextListener接口,监听ServletContext对象的创建和销毁。
首先,编写一个监听器,代码如下:
package cn.liayun.web.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
/*
* 当ServletContext被创建的时候,下面方法执行
* (什么时候创建ServletContext呢?将Web工程发布到Web服务器里面去了,只要一启动Web服务器,
* Web服务器会针对每一个Web应用创建ServletContext)
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext被创建了!!!");
}
/*
* 当ServletContext被销毁的时候,下面方法执行
* (停止服务器,服务器就会把针对于每一个Web应用的ServletContext摧毁)
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext被销毁了!!!");
}
}
然后,在web.xml文件中注册监听器。MyServletContextListener监听器想要能工作,必须注册到事件源上面去,以前我们注册到事件源上面去,都是自己调方法,往事件源上面注册。现在就不能这么干了,想要把监听器注册到ServletContext这个事件源上面去,只须告诉Tomcat服务器,Tomcat服务器会自动帮你注册。监听器也属于Web资源,只要涉及到对Web资源的配置,都要找web.xml文件。
<listener>
<listener-class>cn.liayun.web.listener.MyServletContextListenerlistener-class>
listener>
经过这两个步骤,我们就完成了监听器的编写和注册了,Web服务器在启动时,就会自动把在web.xml中配置的监听器注册到ServletContext对象上,这样开发好的MyServletContextListener监听器就可以对ServletContext对象进行监听了。在以上过程中,大家要注意以下三点:
标签配置好监听器,Web容器就会自动把监听器注册到事件源中;这个技术在开发里面用在哪里呢?这才是我们所关心的,即什么情况下我们才需要监听ServletContext对象的创建和销毁呢?其实可以这样去理解这个监听器,这个监听器说白了可以监听到Web应用的启动和销毁,在做实际开发时,有时候希望Web应用启动时,就初始化一些资源,那么就把初始化一些资源的代码写到contextInitialized方法里面。具体的案例有:
HttpSessionListener接口用于监听HttpSession对象的创建和销毁。
案例:编写一个MyHttpSessionListener类,实现HttpSessionListener接口,监听HttpSession对象的创建和销毁。
首先,编写一个监听器,代码如下:
package cn.liayun.web.listener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session被创建了!!");
System.out.println("创建好的HttpSession的id是:" + se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session被销毁了!!");
}
}
然后,在web.xml文件中注册监听器。
当我们访问某个jsp页面时,HttpSession对象就会创建,此时就可以在HttpSessionListener观察到HttpSession对象的创建过程了,我们可以写一个myindex.jsp页面观察HttpSession对象创建的过程。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>HttpSessionListener监听器监听HttpSession对象的创建title>
head>
<body>
一访问myindex.jsp页面,HttpSession就创建了,创建好的Session的Id是:${pageContext.session.id}
body>
html>
运行结果如下:
由于在web.xml里面配置了session的失效时间,所以在一分钟之后session将被销毁。在以上过程中,大家要注意以下两点:
这个技术在开发里面用在哪里呢?这才是我们所关心的。可以用于统计当前在线人数。一般来说,用户都会开一个浏览器访问服务器,只要他一访问,服务器就会针对他创建一个session,每个用户就有一个session,在实际开发里面,只要统计内存里面有多少session,就能知道当前有多少在线人数了。为了统计当前在线人数,这时可以写一个这样的监听器,只要有一个session被创建就让一个变量count加上1,session被销毁就让变量count减去1,输出count这个值,就能知道当前有多少在线人数了。这一技术在实际开发中的应用可参见我的博客《Java Web基础入门第八十二讲 Listener(监听器)——监听器在开发中的应用(一)》,注意:统计出来的当前在线人数只是一个近似值。
ServletRequestListener接口用于监听ServletRequest对象的创建和销毁。
案例:编写一个MyServletRequestListener类,实现ServletRequestListener接口,监听ServletRequest对象的创建和销毁。
首先,编写一个监听器,代码如下:
package cn.liayun.web.listener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
public class MyServletRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("request被创建了!!!");
sre.getServletRequest().getRemoteAddr();//监听被哪些浏览器访问
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request被销毁了!!!");
}
}
然后,在web.xml文件中注册监听器。
<listener>
<listener-class>cn.liayun.web.listener.MyServletRequestListenerlistener-class>
listener>
测试结果如下:
从运行结果中可以看到,用户每一次访问都会创建request对象,当访问结束后,request对象就会销毁。
这个技术在开发里面用在哪里呢?这才是所我们关心的。这个监听器可以用来做网站性能统计,针对每一个请求,都会有一个request对象创建。