概述
与HttpSession相关的监听器有四个:分别是HttpSessionListener、HttpSessionAttributeListener、HttpSessionBindingListener与HttpSessionActivationListener。
HttpSessionListener
HttpSessionListener是“生命周期监听器”,在HttpSession对象初始化后或结束前,会分别调用sessionCreated()与sessionDestroyed()方法,并传入的HttpSessionEvent,我们可以使用HttpSessionEvent的getSession()取得HttpSession。
声明
方法一:在实现HttpSessionListener的类上标注@WebListener
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
@WebListener() public class SomeSessionListener implements HttpSessionListener {}
方法二:在web.xml中声明
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<listener> <listener-class>cc.openhome.SomeSessionListener</listener-class> </listener>
应用
假设有个应用程序在用户登录后会使用HttpSession对象来进行会话管理。如果想要在应用程序中加上显示目前已登录在线人数的功能,就可以实现HttpSessionListener接口。例如:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
@WebListener() public class LoginSessionListener implements HttpSessionListener { private static int count; public static int getCount() { return count; } @Override public void sessionCreated(HttpSessionEvent se) { LoginSessionListener.count++; } @Override public void sessionDestroyed(HttpSessionEvent se) { LoginSessionListener.count--; } }
可以把这个例子进一步扩充,不只统计在线人数,还可以实现一个查看在线用户信息的列表。
HttpSessionAttributeListener
HttpSessionAttributeListener是“属性改变监听器”,当在会话对象中加入、移除或替换属性时,相对应的attributeAdded()、attributeRemoved()与attributeReplaced()方法就会被调用,并分别传入HttpSessionBindingEvent。HttpSessionBindingEvent有个getName()方法,可以取得属性设置或移除时指定的名称,而getValue()可以取得属性设置或移除时的对象。
声明
方法一:在实现HttpSessionAttributeListener的类上标注@WebListener
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
@WebListener() public class HttpSessionAttrListener implements HttpSessionAttributeListener { @Override public void attributeAdded(HttpSessionBindingEvent event) { //... } @Override public void attributeRemoved(HttpSessionBindingEvent event) { //... } @Override public void attributeReplaced(HttpSessionBindingEvent event) { //... } }
方法二:在web.xml中声明
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<web-app...> ... <listener> <listener-class>cc.openhome.HttpSessionAttrListener</listener-class> </listener> ... <web-app>
HttpSessionBindingListener
HttpSessionBindingListener是“对象绑定监听器”,当实现此接口的对象被加入HttpSession或从中移除时,就会收到通知,并调用对应的valueBound()与valueUnbound()方法,且传入HttpSessionBindingEvent对象,我们可以通过该对象的getSession()取得HttpSession对象。
声明
这个监听器的实现类不需要通过注释或在web.xml中声明。
Demo
当用户输入正确的名称与密码时,创建User实例,并加入HttpSession。如果我们希望这时程序自动从数据库中加载用户的其他数据,如地址、照片等,或是在日志中记录用户登录的信息,可以让User类实现HttpSessionBindingListener接口,在valueBound()方法中,实现查询数据库并补齐User对象中的相关数据等功能。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package com.test; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/login") public class Login extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { doPost(request, response); } @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { String name = request.getParameter("name"); String passwd = request.getParameter("passwd"); // 假设用户的名称和密码都正确 User user = new User(); user.setName(name); user.setPasswd(passwd); // 加入session HttpSession session = request.getSession(); session.setAttribute("UUID", user); // 检查属性有没有补全 User user2 = (User) session.getAttribute("UUID"); response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); System.out.println(user2); response.getWriter().write(user2.toString()); } }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package com.test; import javax.servlet.*; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; @WebListener public class User implements HttpSessionBindingListener { private String name; private transient String passwd; private String sex; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", passwd='" + passwd + '\'' + ", sex='" + sex + '\'' + ", age=" + age + '}'; } @Override public void valueBound(HttpSessionBindingEvent event) { try { Thread.sleep(1000); // 测试这个方法是不是阻塞的。结果:是阻塞的,页面一直会等待 } catch (InterruptedException e) { e.printStackTrace(); } User user = (User) event.getValue(); user.setAge(18); user.setSex("女"); } @Override public void valueUnbound(HttpSessionBindingEvent event) { } }
测试地址
http://127.0.0.1/login?name=zs&passwd=123
测试结果
User{name='zs', passwd='123', sex='女', age=18}
HttpSessionActivationListener
HttpSessionActivationListener是“对象迁移监听器”,其中定义了两个方法sessionWillPassivate()、sessionDidActivate()。很多情况下,几乎不会使用到HttpSessionActivationListener。在使用到分布式环境时,应用程序的对象可能分散在多个JVM中。当HttpSession要从一个JVM迁移至另一个JVM时,必须先在原本的JVM上序列化所有的对象,在这之前若对象有实现HttpSessionActivationListener,就会调用sessionWillPassivate()方法,如果HttpSession中有些对象类成员无法作序列化,就可以做些替代处理。而HttpSession迁移至另一个JVM后,会对所有对象作反序列化,此时会调用sessionDidActivate()方法。