8.3 SessionListeners 8.3.1HttpSessionListener

8.3 SessionListeners

一共有四个HttpSession相关的监听器接口:HttpSessionListener,HttpSessionActivationListenerHttpSessionAttributeListenerHttpSessionBindingListener。这四个接口都在javax.servlet.http包中,下面分别对它们进行介绍。

8.3.1HttpSessionListener

当一个HttpSession创建或者销毁时,容器都会通知所有的HttpSessionListener监听器,HttpSessionListener接口有两个方法:sessionCreatedsessionDestroyed

1
2
void sessionCreated(HttpSessionEvent event)
void sessionDestroyed(HttpSessionEvent event)

这两个方法都可以接收到一个继承于java.util.EventHttpSessionEvent对象。可以通过调用形参列表中的HttpSessionEvent对象的getSession方法来获取当前的HttpSessiongetSession方法如下:

1
HttpSession getSession()

实例

app08a应用中的SessionListener类。这个监听器来统计HttpSession的数量。它使用了一个AtomicInteger对象来统计,并且将这个对象保存成ServletContext范围的属性。每当有一个HttpSession被创建时,这个AtomicInteger对象就会加一。每当有一个HttpSession被销毁时,这个AtomicInteger对象就会减一。所以这个对象会保存着当前存活的HttpSession数量。这里使用了AtomicInteger 来代替Integer类型是为了保证能同步进行加减的操作。

SessionListener类

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package app08a.listener;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class SessionListener
implements
HttpSessionListener,
ServletContextListener
{
// 项目启动时创建ServletContext对象时调用
@Override
public void contextInitialized(ServletContextEvent sce)
{
ServletContext servletContext =
sce.getServletContext();
servletContext.setAttribute("userCounter",
new AtomicInteger());
}
// 项目销毁时销毁ServletContext对象时调用
@Override
public void contextDestroyed(ServletContextEvent sce)
{}
// 一个浏览器第一次访问该项目时会创建一个对应的Session内置对象
// 创建Session对象时调用该方法
@Override
public void sessionCreated(HttpSessionEvent se)
{
HttpSession session = se.getSession();
ServletContext servletContext =
session.getServletContext();
AtomicInteger userCounter =
(AtomicInteger) servletContext
.getAttribute("userCounter");
//加1
int userCount = userCounter.incrementAndGet();
System.out.println("userCount incremented to :"
+ userCount);
}
//Session内置对象被销毁时调用
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
HttpSession session = se.getSession();
ServletContext servletContext =
session.getServletContext();
AtomicInteger userCounter =
(AtomicInteger) servletContext
.getAttribute("userCounter");
//减1
int userCount = userCounter.decrementAndGet();
System.out.println("----------"
+ " userCount decremented to:"
+ userCount);
}
}

SessionListener类实现了ServletContextListenerHttpSessionListener接口。所以需要实现这两个接口的所有方法。

contextInitialized方法说明

contextInitialized方法创建了一个AtomicInteger对象并将其保存在ServletContextuserCounter属性中。由于是在应用启动的时候创建,因此这个AtomicInteger对象的初始值为0

1
2
3
4
5
6
7
8
9
// 项目启动时创建ServletContext对象时调用
@Override
public void contextInitialized(ServletContextEvent sce)
{
ServletContext servletContext =
sce.getServletContext();
servletContext.setAttribute("userCounter",
new AtomicInteger());
}

sessionCreated方法说明

sessionCreated方法在每个HttpSession创建时被调用。当有HttpSession创建时,从ServletContext中获取userCounter属性。然后调用userCounterincrementAndGet 方法让计数加一。最后在控制台将userCounter的值打印出来,可以直观地看到效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建Session对象时调用该方法
@Override
public void sessionCreated(HttpSessionEvent se)
{
HttpSession session = se.getSession();
ServletContext servletContext =
session.getServletContext();
AtomicInteger userCounter =
(AtomicInteger) servletContext
.getAttribute("userCounter");
//加1
int userCount = userCounter.incrementAndGet();
System.out.println("userCount incremented to :"
+ userCount);
}

sessionDestroyed方法说明

sessionDestroyed方法会在HttpSession销毁之前被调用。这个方法的实现和sessionCreated类似,只不过对userCounter改为减一操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Session内置对象被销毁时调用
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
HttpSession session = se.getSession();
ServletContext servletContext =
session.getServletContext();
AtomicInteger userCounter =
(AtomicInteger) servletContext
.getAttribute("userCounter");
//减1
int userCount = userCounter.decrementAndGet();
System.out.println("----------"
+ " userCount decremented to:"
+ userCount);
}

运行效果

可以通过不同的浏览器访问countries.jsp页面来查看监听器的效果,下面是countries.jsp的访问URL
http://localhost:8080/app08a/countries.jsp
第一次访问时,Java IDE控制台会打印如下信息:

1
userCount incremented to :1

用同一个浏览器再次访问这个URL并不会改变userCounter,因为这属于同一个HttpSession。使用不同的浏览器访问才能增加userCounter的值。这时候控制台打印内容如下:

1
2
userCount incremented to :1
userCount incremented to :2

如果你有时间等待HttpSession过期的话,在控制台也能看到HttpSession销毁时打印的信息,如下所示:

1
2
---------- userCount decremented to:1
---------- userCount decremented to:0