监视器
监听器的概述:
概念:
用于监听Web程序在执行过程中作用域(上下文域、会话域、请求域)中发生的一些事件,如:监听作用域的创建和销毁,增加属性,修改属性,删除属性值等。监听器对象可以在事情发生前、发生后做一些必要的处理。
监听的两种类型:
对域对象的创建与销毁的行为进行监听
对域中的属性增删改的行为进行监听
所有的监听器都是由事件触发时执行,不由用户主动调用。
使用场景:
统计在线人数
显示登录的用户的详细信息
- Web项目启动和关闭时处理的工作
监听机制的组成
监听机制的对象 | 描述 |
---|---|
事件源 | 发出事件的对象,域对象:上下文域ServletContext,会话域,请求域 |
事件 | 事件本身,ServletContextEvent类,做为参数传递给监听者 |
监听者 | 对事件进行处理的类,这个类需要实现监听器的接口,XxxListener接口 |
监听器的分类
事件源 | 监听器接口 | 时机 |
---|---|---|
ServletContext | ServletContextListener | 上下文域创建和销毁的接口 |
ServletContext | ServletContext**Attribute**Listener | 上下文域中属性变化的监听接口 |
HttpSession | HttpSessionListener | 会话域创建和销毁的接口 |
HttpSession | HttpSession**Attribute**Listener | 会话域中属性变化的监听接口 |
ServletRequest | ServletRequestListener | 请求域创建和销毁的接口 |
ServletRequest | ServletRequest**Attribute**Listener | 请求域中属性变化的监听接口 |
ServletContextListener监听器
- 作用: 用于监听上下文对象的创建和销毁
运行时机:
- 创建:服务器启动加载当前项目的时候
- 销毁:服务器关闭的时候
方法:
- 接口中的方法
功能 void contextDestroyed(ServletContextEvent sce) 用于监听上下文对象销毁时方法,传递了事件对象 void contextInitialized(ServletContextEvent sce) 用于监听上下文对象创建时方法 ServletContextEvent中的方法
- ServletContext getServletContext() 得到上下文对象
ServletContextAttributeListener监听器
- 作用:监听上下文域中属性变化
时机:
- 增:application.setAttribute()
- 删:application.removeAttribute()
- 改:application.setAttribute(同名)
- 上面每一个动作都会触发下面的方法的
接口方法中的方法:
接口中的方法 功能 void attributeAdded(ServletContextAttributeEvent event) 添加属性的时候监听方法 void attributeRemoved(ServletContextAttributeEvent event) 删除属性的时候监听方法 void attributeReplaced(ServletContextAttributeEvent event) 修改属性的时候监听方法 ServletContextAttributeEvent对象中的方法
ServletContextAttributeEvent对象中的方法 功能 String getName() 得到属性的名字 Object getValue() 得到属性的值 ServletContext getServletContext() 得到上下文对象 示范
<%
//添加属性
application.setAttribute("user", "猪八戒");
//修改属性
application.setAttribute("user", "嫦娥");
//删除属性
application.removeAttribute("user");
%>
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("上下文域被创建了, 得到上下文域对象:" + sce.getServletContext());
}
//上下文域销毁
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("上下文域被销毁");
}
//属性添加
@Override
public void attributeAdded(ServletContextAttributeEvent scab) {
System.out.println("添加了属性名:" + scab.getName() + ",属性值:" + scab.getValue());
}
//属性删除
@Override
public void attributeRemoved(ServletContextAttributeEvent scab) {
System.out.println("删除了属性名:" + scab.getName() + ",属性值:" + scab.getValue());
}
//属性修改
@Override
public void attributeReplaced(ServletContextAttributeEvent scab) {
System.out.println("修改前属性名:" + scab.getName() + ",属性值:" + scab.getValue());
System.out.println("修改后属性名:" + scab.getName() + ",属性值:" + scab.getServletContext().getAttribute( scab.getName()));
}
HttpSessionListener的概述:
- 作用: 会话域创建和销毁监听器
时机:
创建:用户第1次访问服务器,并且调用request.getSession()
销毁:会话过期
- setMaxInactiveInterval(秒)
- web.xml配置分
- invalidate() 立即失效
- 接口中的方法
- void sessionCreated(**HttpSessionEven**t se) 会话创建监听方法
- void sessionDestroyed(HttpSessionEvent se) 会话销毁监听方法
HttpSessionAttributeListener监听器
- 作用: 对会话域中的属性增删改监听
- 时机:
- 增:session.setAttribute()
- 删:session.removeAttribute()
- 修:session.setAttribute(同名)
- 上面的每一个动作都会触发下面的方法
接口中的方法
接口中的方法 功能 void attributeAdded(HttpSessionBindingEvent event) 会话域中添加属性的时候监听方法 void attributeRemoved(HttpSessionBindingEvent event) 会话域中删除属性的时候监听方法 void attributeReplaced(HttpSessionBindingEvent event) 会话域中修改属性的时候监听方法
ServletRequestListener的作用
- 作用:
请求的创建和销毁监听器 时机:
- 创建:发送请求的时候
- 销毁:响应结束的时候
接口中的方法
接口中的方法 功能 void requestDestroyed(ServletRequestEvent sre) 请求对象销毁的时候处理方法 void requestInitialized(ServletRequestEvent sre) 请求对象创建的时候处理方法
ServletRequestAttributeListener的使用
请求域中的属性的创建和销毁监听器
接口中的方法 | 功能 |
---|---|
void attributeAdded(ServletRequestAttributeEvent srae) | 请求域中添加属性的监听方法 |
void attributeRemoved(ServletRequestAttributeEvent srae) | 请求域中删除属性的监听方法 |
void attributeReplaced(ServletRequestAttributeEvent srae) | 请求域中修改属性的监听方法 |
案例 统计网站在线访客人数
实现思路:
- 服务器创建会话的个数,与用户访客的个数是相同的。
- 设计一个成员变量用于存储网站访客的人数: int onLineCount = 0;
- 在sessionCreated方法中onLineCount加1
- 把onLineCount的值放入上下文域中,供所有用户共享。
- 在sessionDestoryed中,用户数量减1,onLineCount–,并更新context域中的值。
- 在页面上,从context域中取出用户数量,输出。
- 创建JSP页面显示用户数,创建logout.jsp退出。
- 如果要用线程安全的计数器,可以使用AtomicInteger类
/*
统计在线人数
*/
public class CounterUserListener implements HttpSessionListener {
//设计一个成员变量用于存储网站访客的人数,避免线程安全问题
private AtomicInteger onLineCount = new AtomicInteger();
//只要创建一个新的会话,人数加1
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("创建会话:" + se.getSession().getId());
//在sessionCreated方法中onLineCount加1
// onLineCount++;
onLineCount.incrementAndGet(); //相当于加1
//把onLineCount的值放入上下文域中,供所有用户共享。
se.getSession().getServletContext().setAttribute("count", onLineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("销毁会话:" + se.getSession().getId());
//在sessionDestoryed中,用户数量减1,
// onLineCount--;
onLineCount.decrementAndGet(); //相当于减1
//并更新context域中的值
se.getSession().getServletContext().setAttribute("count", onLineCount);
}
}
JSP
<body>
<h2>您好,你是第${applicationScope.count}个在线的访客</h2>
<a href="logout.jsp">退出</a>
</body>
AtomicInteger类
JAVA 中无锁的线程安全整数 AtomicInteger介绍和使用
在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
是一个原子操作
AtomicInteger Atomic =new AtomicInteger();
Atomic.incrementAndGet();//相当于加1
Atomic.decrementAndGet();//相当于减1
Java.util.concurrent中实现的原子操作类包括:
AtomicBoolean、AtomicInteger、AtomicIntegerArray、AtomicLong、AtomicReference、AtomicReferenceArray。