Java监听器(Listener)

Servlert的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,随着web应用的启动而启动,只初始化一次,随web应用的停止而销毁。

1.主要作用:

application、session、request三个对象创建、销毁时候或者往其中添加修改删除属性时自动执行代码的功能组件

做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者一个固定的对象等等

1
2
3
4
5
6
7

public interface ServletContextListener extends EventListener {
//应用监听器的初始化方法
public void contextInitialized(ServletContextEvent sce);
//应用监听器的销毁方法
public void contextDestroyed(ServletContextEvent sce);
}
1.ServletContextListener:对Servlet上下文的创建和销毁进行监听。
1
2
3
4
5
6
7
8
9
10
11
class test implements ServletContextListener{
/**
* 当Servlet 容器启动Web 应用时调用该方法。在调用完该方法之后,容器再对Filter 初始化,
* 并且对那些在Web 应用启动时就需要被初始化的Servlet 进行初始化。
*/
contextInitialized(ServletContextEvent sce) ;
/**
* 当Servlet 容器终止Web 应用时调用该方法。在调用该方法之前,容器会先销毁所有的Servlet 和Filter 过滤器。
*/
contextDestroyed(ServletContextEvent sce);
}
2.ServletContextAttributeListener:监听Servlet上下文属性的添加、删除和替换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class test implements ServletContextAttributeListener{
//在程序运行过程中,req.getServletContext().setAttribute(“”,something); 时发挥作用
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("添加了一个ServletContext属性");

}
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("移除了一个ServletContext属性");
}
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("修改了一个ServletContext属性的作用范围");
}
}
3.HttpSessionListener:对Session的创建和销毁进行监听。
1
2
3
4
5
6
7
8
9
class test implements HttpSessionListener{
//session创建
public void sessionCreated(HttpSessionEvent se);
//session销毁
public void sessionDestroyed(HttpSessionEvent se);
//HttpSessionEvent事件:
//取得当前操作的session
public HttpSession getSession();
}

补充:session的销毁有两种情况:1.session超时

​ 2.通过调用session对象的invalidate()方法使session失效。

4.HttpSessionAttributeListener:对Session对象中属性的添加、删除和替换进行监听。
1
2
3
4
5
6
7
8
9
10
class test implements HttpSessionAttributeListener{
public void attributeAdded(HttpSessionBindingEvent se);//增加属性
public void attributeRemoved(HttpSessionBindingEvent se);//删除属性
public void attributeReplaced(HttpSessionBindingEvent se);//替换属性

//HttpSessionBindingEvent事件:
public String getName();//取得属性的名称
public Object getValue();//取得属性的值
public HttpSession getSession();//取得当前的session
}
5.ServletRequestListener:对请求对象的初始化和销毁进行监听。
1
2
3
4
5
6
7
class test implements ServletRequestListener{
public void requestInitialized(ServletRequestEvent sre);//request初始化,对实现客户端的请求进行监听
public void requestDestroyed(ServletRequestEvent sre);//对销毁客户端进行监听,即当执行request.removeAttribute("XXX")时调用
//ServletRequestEvent事件:
public ServletRequest getServletRequest();//取得一个ServletRequest对象
public ServletContext getServletContext();//取得一个ServletContext(application)对象
}
6.ServletRequestAttributeListener:对请求对象属性的添加、删除和替换进行监听。
1
2
3
4
5
6
7
8
class test implements ServletRequestAttributeListener{
public void attributeAdded(ServletRequestAttributeEvent srae);//增加属性
public void attributeRemoved(ServletRequestAttributeEvent srae);//属性删除
public void attributeReplaced(ServletRequestAttributeEvent srae);//属性替换(第二次设置同一属性)
//ServletRequestAttributeEvent事件:能取得设置属性的名称与内容
public String getName();//得到属性名称
public Object getValue();//取得属性的值
}

2.常见使用场景:

初始化基础数据
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
/**
* @author yhwang
* @date 2021年06月24日 17:55
*/
@Component
public class ListenerTest implements ServletContextListener, ApplicationContextAware {
//其实这个就是spring的IOC容器-spring上下文应用程序 实现了ApplicationContextAware接口可以获取当前的上下文对象
private static ApplicationContext applicationContext;
@SuppressWarnings("static-access")
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}

//应用监听器的初始化方法
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//整个javaWeb应用页面作用域servlet上下文,生命周期整个应用,可以往域对象里面添加,删除,修改数据;
ServletContext servletContext = servletContextEvent.getServletContext();
StudentService studentService = (StudentService) applicationContext.getBean("studentService");// 查询学生信息
System.out.println(studentService.list());
servletContext.setAttribute("学生列表",studentService.list());
}
//应用监听器的销毁方法
@Override
public void contextDestroyed(ServletContextEvent sce) {

}
}
统计当前在线人数
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
@Component
public class SessionListenerTest implements HttpSessionListener {

public static int ONLINE_USERS_TOTAL = 0;

/**
* session创建时
* @param httpSessionEvent
*/
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
ServletContext application = httpSessionEvent.getSession().getServletContext();
Integer online_users_total = (Integer) application.getAttribute("ONLINE_USERS_TOTAL");
// 如果用户登录,ONLINE_USERS_TOTAL
if(ONLINE_USERS_TOTAL==0){
application.setAttribute("ONLINE_USERS_TOTAL",1);
}else{
application.setAttribute("ONLINE_USERS_TOTAL",online_users_total);
}
ONLINE_USERS_TOTAL++;
System.out.println(ONLINE_USERS_TOTAL+"login");
}

/**
* session销毁时
* @param httpSessionEvent
*/
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
// 如果用户退出,ONLINE_USERS_TOTAL
ServletContext application = httpSessionEvent.getSession().getServletContext();
ONLINE_USERS_TOTAL--;
application.setAttribute("ONLINE_USERS_TOTAL",ONLINE_USERS_TOTAL);
System.out.println(ONLINE_USERS_TOTAL+"logout");
}
}
定期清理session
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
/**
* @author yhwang
* @date 2021年06月24日 18:57
* @description 当网站用户量增加时,session占用的内存会越来越大,这时session的管理,将会是一项很大的
* 系统开销,为了高效的管理session,我们可以写一个监听器,定期清理掉过期的session
*/
@Component
public class SessionScanerListener implements HttpSessionListener, ServletContextListener {
// 创建一个线程安全的集合,用来存储session
@SuppressWarnings("unchecked")
List<HttpSession> sessionList = Collections.synchronizedList(new LinkedList<HttpSession>());
private Object lock = new Object();

public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("session 创建成功...");
HttpSession httpSession = httpSessionEvent.getSession();
synchronized (lock){
sessionList.add(httpSession);
}
}

public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("session 销毁成功...");
}
// web应用关闭时触发contextDestroyed事件
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("web应用关闭...");
}

// web应用启动时触发contextInitialized事件
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("web应用初始化...");
// 创建定时器
Timer timer = new Timer();
// 每隔30秒就定时执行任务
timer.schedule(new MyTask(sessionList,lock), 0, 1000*30);
}
}
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
public class MyTask  extends TimerTask {
private List<HttpSession> list;
// 存储传递过来的锁
private Object lock;
// 构造方法
public MyTask(List<HttpSession> list, Object lock){
this.list = list;
this.lock = lock;
}
@Override
public void run() {
// 考虑到多线程的情况,这里必须要同步
synchronized (lock){
System.out.println("定时器开始执行...");
ListIterator<HttpSession> listIterator = list.listIterator();
while(listIterator.hasNext()){
HttpSession httpSession = listIterator.next();
// httpSession.getLastAccessedTime() = session的最后访问时间
if(System.currentTimeMillis() - httpSession.getLastAccessedTime() > 1000*30){
// 手动销毁session
httpSession.invalidate();
// 从集合中移除已经被销毁的session
listIterator.remove();
}
}
}
}
}