在Servlet/JSP中除了ServletContextListener外,还有ServletRequestListener、HttpSessionListener等监听器,可以监听请求、会话对象生命周期;ServletRequestAttributeListener、HttpSessionAttributeListener、ServletContextAttributeListener可以监听属性的添加、删除或替换;HttpSessionBindingListener、HttpSessionActivationListener可以监听会话属性对象的绑定、删除。
生命周期监听器
所谓的生命周期监听器,就是可以在某个对象生成到被容器销毁之前,监听对象生命周期的状态变化。如在应用程序初始化或结束前,会分别调用contextInitialized()与contextDestroyed()方法,通过传入的ServletContextEvent取得ServletContext,以针对应用程序作出相对应的初始化或结束处理。
-
ServletContextListener
contextInitialized(sce: ServletContextEvent): voidcontextDestroyed(sce: ServletContextEvent): void
-
ServletContextEvent
ServletContextEvent(source: ServletContext)getServletContext(): ServletContext
如果想要在ServletRequest(HttpServletRequest)对象生成或结束时,做些相应动作,则可以实现ServletRequestListener。
-
ServletRequestListener
requestInitialized(sre: ServletRequestEvent): voidrequestDestroyed(sce: ServletRequestEvent): void
-
ServletRequestEvent
ServletRequestEvent(sc: ServletContext, request: ServletRequest)getServletRequest(): ServletRequestgetServletContext(): ServletContext
如果想要在HttpSession对象生成或结束时,做些相应动作,则可以实现HttpSessionListener。
-
HttpSessionListener
sessionCreated(sre: HttpSessionEvent): voidsessionDestroyed(sce: HttpSessionEvent): void
-
HttpSessionEvent
HttpSessionEvent(source: HttpSession)getSession(): HttpSession
一个HttpSessionListener应用实例如下,假设有个应用程序在用户登录时会使用HttpSession对象来进行会话管理:
//...
public class Login extends HttpServlet{
//...
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("abc".equals(username) && "123".equals(password)) {
request.getSession().setAttribute("login", username);
request.getRequestDispatcher("user.jsp")
.forward(request, response);
} else {
response.sendRedirect("login.html");
}
}
}
这个Servlet在用户登录验证后,会取得HttpSession实例并设置属性。如果想要在应用程序中,加上显示目前已登录在线人数的功能,则可以实现HttpSessionListener接口。例如:
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class LoginListener implements HttpSessionListener {
private static int count;
public static int getCount() {
return count;
}
@Override
public void sessionCreated(HttpSessionEvent se) {
count++;
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
count--;
}
}
为了使用这个监听器,要在web.xml中加以设置
<web-app ...>
<listener>
<listener-class>club.chuxing.LoginListener</listener-class>
</listener>
</web-app>
要显示在线人数时,使用LoginListener.getCount()即可。
属性操作监听器
在Servlet/JSP中,有三个对象可以设置属性,分别是ServletContext、HttpSession和ServletRequest。如果想要在这些对象被设置、删除或替换属性时,收到通知以进行一些动作,则可以实现相对应的ServletContextAttributeListener、HttpSessionAttributeListener和ServletRequestAttributeListener接口。
-
ServletContextAttributeListener
attributeAdded(scab: ServletContextAttributeEvent): voidattributeRemoved(scab: ServletContextAttributeEvent): voidattributeReplaced(scab: ServletContextAttributeEvent): void
-
HttpSessionAttributeListener
attributeAdded(se: HttpSessionBindingEvent): voidattributeRemoved(se: HttpSessionBindingEvent): voidattributeReplaced(se: HttpSessionBindingEvent): void
-
ServletRequestAttributeListener
attributeAdded(srae: ServletRequestAttributeEvent): voidattributeRemoved(srae: ServletRequestAttributeEvent): voidattributeReplaced(srae: ServletRequestAttributeEvent): void
当在这三个对象中加入、删除或替换属性时,相对应的方法就会被调用。如果要使用这几个监听器,必须同样在web.xml中使用<listener>与<listener-class>进行设置。
会话属性类监听器
前面几个监听器都必须在web.xml中进行设置,这里所要介绍的HttpSessionBindingListener与HttpSessionActivationListener,则是让即将加入HttpSession的属性对象实现,HttpSession在适当的时机就会直接调用接口上对应的方法,不必在web.xml中做任何设置。
HttpSessionBindingListener
如果有个即将加入HttpSession的属性对象,希望在设置给HttpSession成为属性或从HttpSession中删除时,可以收到HttpSession的通知,则可以让该对象实现HttpSessionBindingListener接口。
当属性对象被加入到HttpSession中或从中删除时,就会调用对应的valueBound()与valueUnbound()方法。
-
HttpSessionBindingListener
valueBound(event: HttpSessionBindingEvent): voidvalueUnbound(event: HttpSessionBindingEvent): void
接下来是该接口的一个范例,假设有登录程序如下:
//...
public class Login extends HttpServlet{
//...
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("abc".equals(username) && "123".equals(password)) {
User user = new User(name);
request.getSession().setAttribute("login", user);
request.getRequestDispatcher("user.jsp")
.forward(request, response);
} else {
response.sendRedirect("login.html");
}
}
}
当用户输入正确的用户名和密码时,首先会以用户名称来创建User实例,而后加入HttpSession中作为属性。当希望User实例被加入成为HttpSession属性时,可以自动从数据库中加载用户的其他数据,比如地址、相片等,并在日志中记录用户登录的信息;而当HttpSession失效或者因用户注销而User实例从HttpSession中删除时,则在日志中记录用户注销的信息。在这种情况下,可以让User类实现HttpSessionBindingListener接口。例如:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
public class User implements HttpSessionBindingListener {
private String name;
private String otherData;
public User(String name) {
this.name = name;
}
@Override
public void valueBound(HttpSessionBindingEvent event) {
this.otherData = name + ": query data from database...";
Logger.getLogger(User.class.getName()).log(Level.SEVERE, this.name + " login...", event);
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
Logger.getLogger(User.class.getName()).log(Level.SEVERE, this.name + " logout...", event);
}
//Getter and Setter
}
HttpSessionActivationListener
HttpSessionActivationListener定义了两个方法sessionWillPassivate()与sessionDidActivate()。
-
HttpSessionActivationListener
sessionWillPassivate(se: HttpSessionEvent): voidsessionDidActivate(se: HttpSessionEvent): void
大部分情况下,几乎不会使用到HttpSessionActivationListener。在使用到分布式环境时,应用程序的兑现可能分散在多个JVM中。当HttpSession要从一个JVM迁移至另一个JVM时,必须现在原本的JVM上序列化所有的属性对象。在这之前若属性对象实现了HttpSessionActivationListener,就会调用sessionWillPassivate()方法。当HttpSession迁移至另一个JVM后,就会对所有对象做反序列化,此时就会调用sessionDidActivate()方法。
要实现序列化的对象必须实现Serializable接口,如果在HttpSession对象中,有些类别成员无法做序列化,则可以在sessionWillPassivate()方法中做些替代处理来保存该成员的状态,而在sessionDidActivate()方法中做某些恢复该成员状态的动作。