1、监听器的基本知识
1.1、概念
监听器就是一个实现特定接口的普通java程序(事件监听器),这个程序专门用于监听另一个java对象(事件源)的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。Java的事件监听器是由事件类和监听接口组成,其中,JAVA中监听接口是继承java.util.EventListener的类,事件类继承java.util.EventObject的类。
1.2、监听器三要素
在监听器中涉及到了三个重要的组件,即事件源,事件对象和事件监听器。当事件源发生某个动作的时候,它会调用事件监听器的方法,并在调用事件监听器方法的时候把事件对象传递进去。在监听器中就可以通过事件对象获取得到事件源,从而对事件源进行操作。
2、Servlet规范中定义的监听器
在Servlet规范中定义的监听器有很多,分类的方式也有很多,这里我将以事件源对象的角度进行分类:
- ServletContext相关监听器:
- ServletContextListener
ServletContext域对象监听器 - ServletContextAttributeListener
ServletContext域对象存储数据监听器,即监听其中数据变化的监听器
- ServletRequest相关监听器:
- ServletRequestListener
ServletRequest域对象监听器 - ServletRequestAttributeListener
ServletRequest域对象存储数据监听器,即监听其中数据变化的监听器
- HttpSession相关监听器:
- HttpSessionListener
HttpSession域对象监听器,其中关联的事件对象是HttpSessionEvent。 - HttpSessionIdListener
HttpSession域对象中ID变化的监听器。和HttpSessionListener 一样,关联的事件对象是HttpSessionEvent。 - HttpSessionActivationListener
HttpSession域对象中的JavaBean对象对钝化和恢复的监听器。和HttpSessionListener 、HttpSessionIdListener 一样,关联的事件对象是HttpSessionEvent。 - HttpSessionAttributeListener
HttpSession域对象存储数据监听器,即监听其中数据变化的监听器。其中关联的事件对象是HttpSessionBindingEvent。 - HttpSessionBindingListener
HttpSession域对象中的JavaBean对象对绑定和解绑的监听器。和HttpSessionAttributeListener 一样,关联的事件对象是HttpSessionBindingEvent。
2.1、ServletContext相关的监听器
2.1.1、ServletContext的初始化、销毁监听器
ServletContext的初始化、销毁监听器由ServletContext、ServletContextListener、ServletContextEvent组成。其中ServletContextEvent对应事件对象,ServletContextListener对应事件监听器接口,ServletContext对应事件源。
在ServletContextListener事件监听器接口中,定义了两个方法,其中contextInitialized()方法用来监听ServletContext对象的初始化事件,contextDestroyed()方法用来监听ServletContext对象的销毁事件。两个方法的参数都是ServletContextEvent,即事件对象。
ServletContextListener事件监听器接口:
package javax.servlet;
import java.util.EventListener;
public interface ServletContextListener extends EventListener {
public void contextInitialized(ServletContextEvent sce);
public void contextDestroyed(ServletContextEvent sce);
}
ServletContextEvent事件对象:
package javax.servlet;
public class ServletContextEvent extends java.util.EventObject {
private static final long serialVersionUID = 1L;
public ServletContextEvent(ServletContext source) {
super(source);
}
public ServletContext getServletContext() {
return (ServletContext) super.getSource();
}
}
2.1.2、ServletContext中属性变化的监听器
ServletContext中属性变化的监听器由ServletContext中的对象(可能是任意的JavaBean对象)、ServletContextAttributeListener、ServletContextAttributeEvent组成。其中ServletContextAttributeEvent对应事件对象,ServletContextAttributeListener对应事件监听器接口,ServletContext中的对象对应事件源。
在ServletContextAttributeListener事件监听器接口中,定义了三个方法,其中attributeAdded()方法用来监听ServletContext对象中新的属性被新增加时的事件,attributeRemoved()方法用来监听ServletContext对象中原有的属性被移除时的事件。attributeReplaced()方法用来监听ServletContext对象中原有属性被替换时的事件。这三个方法的参数都是ServletContextAttributeEvent,即事件对象。
ServletContextAttributeListener事件监听器接口:
package javax.servlet;
import java.util.EventListener;
public interface ServletContextAttributeListener extends EventListener {
public void attributeAdded(ServletContextAttributeEvent scae);
public void attributeRemoved(ServletContextAttributeEvent scae);
public void attributeReplaced(ServletContextAttributeEvent scae);
}
ServletContextAttributeEvent事件对象:
package javax.servlet;
public class ServletContextAttributeEvent extends ServletContextEvent {
private static final long serialVersionUID = 1L;
private final String name;
private final Object value;
public ServletContextAttributeEvent(ServletContext source, String name,
Object value) {
super(source);
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public Object getValue() {
return this.value;
}
}
2.2、ServletRequest相关的监听器
ServletRequest的监听器和ServletContext的监听器类似,也是包括了ServletRequest对象的初始化、销毁监听器和ServletRequest对象中属性变化的监听器。除了事件源本身不一样外,其他的用法和ServletContext监听器基本一样。
2.2.1、ServletRequest的初始化、销毁监听器
ServletRequest的初始化、销毁监听器由ServletRequest、ServletRequestListener、ServletRequestEvent组成。其中ServletRequestEvent对应事件对象,ServletRequestListener对应事件监听器接口,ServletContext对应事件源。
在ServletRequestListener事件监听器接口中,定义了两个方法,其中requestInitialized()方法用来监听ServletRequest对象的初始化事件,requestDestroyed()方法用来监听ServletRequest对象的销毁事件。两个方法的参数都是ServletRequestEvent,即事件对象。
ServletRequestListener、ServletRequestEvent源码和ServletContext中的类似,略……。
2.2.2、ServletRequest中属性变化的监听器
ServletRequest中属性变化的监听器由ServletRequest中的对象(可能是任意的JavaBean对象)、ServletRequestAttributeListener、ServletRequestAttributeEvent组成。其中ServletRequestAttributeEvent对应事件对象,ServletRequestAttributeListener对应事件监听器接口,ServletRequest中的对象对应事件源。
在ServletRequestAttributeListener事件监听器接口中,定义了三个方法,其中attributeAdded()方法用来监听ServletRequest对象中新的属性被新增加时的事件,attributeRemoved()方法用来监听ServletRequest对象中原有的属性被移除时的事件。attributeReplaced()方法用来监听ServletRequest对象中原有属性被替换时的事件。这三个方法的参数都是ServletRequestAttributeEvent,即事件对象。
ServletRequestAttributeListener、ServletRequestAttributeEvent源码和ServletContext中的类似,略……。
2.3、HttpSession相关的监听器
HttpSession的监听器除了和上述ServletContext、ServletRequest对象类似的监听器外,还提供了一些其他的监听器,比如HttpSessionActivationListener、HttpSessionBindingListener等,而且HttpSession的监听器在实际的应用开发过程中,使用的也是比较多的。下面我们就分别来了解学习相关的监听器对象。
2.3.1、HttpSession的初始化、销毁监听器
HttpSession的初始化、销毁监听器由HttpSession、HttpSessionListener、HttpSessionEvent组成。其中HttpSessionEvent对应事件对象,HttpSessionListener对应事件监听器接口,HttpSession对应事件源。
在HttpSessionListener事件监听器接口中,定义了两个方法,其中sessionCreated()方法用来监听HttpSession对象的初始化事件,sessionDestroyed()方法用来监听HttpSession对象的销毁事件。两个方法的参数都是HttpSessionEvent,即事件对象。
HttpSessionListener事件监听器接口:
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionListener extends EventListener {
public void sessionCreated(HttpSessionEvent se);
public void sessionDestroyed(HttpSessionEvent se);
}
HttpSessionEvent事件对象:
package javax.servlet.http;
public class HttpSessionEvent extends java.util.EventObject {
private static final long serialVersionUID = 1L;
public HttpSessionEvent(HttpSession source) {
super(source);
}
public HttpSession getSession() {
return (HttpSession) super.getSource();
}
}
2.3.2、HttpSession域对象的ID变化监听器
&mesp;HttpSessionIdListener监听器和HttpSessionListener的用法基本一样,其中,事件对象也一样都是HttpSessionEvent。在HttpSessionIdListener监听器接口中定义了sessionIdChanged()方法,用来监听HttpSession域对象中的ID变化。
HttpSessionIdListener事件监听器接口:
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionIdListener extends EventListener {
public void sessionIdChanged(HttpSessionEvent se, String oldSessionId);
}
2.3.3、HttpSession中属性变化(新增、移除、替换)的监听器
HttpSession中属性变化的监听器由HttpSession中的对象(可能是任意的JavaBean对象)、HttpSessionAttributeListener、HttpSessionBindingEvent组成。其中HttpSessionBindingEvent对应事件对象,HttpSessionAttributeListener对应事件监听器接口,HttpSession中的对象对应事件源。
在HttpSessionAttributeListener事件监听器接口中,定义了三个方法,其中attributeAdded()方法用来监听HttpSession对象中新的属性被新增加时的事件,attributeRemoved()方法用来监听HttpSession对象中原有的属性被移除时的事件。attributeReplaced()方法用来监听HttpSession对象中原有属性被替换时的事件。这三个方法的参数都是HttpSessionBindingEvent,即事件对象。
细心的同学已经发现了,在监听HttpSession域对象属性变化的监听对象中,对应的事件对象命名和前面讲过的ServletContextAttributeEvent、ServletRequestAttributeEvent命名规则不太一样了,因为前面都是*AttributeEvent的格式,而这里使用了HttpSessionBindingEvent类,这是因为HttpSession域对象属性监听器和HttpSessionBindingListener域对象属性解绑和绑定监听器使用了同一个类作为事件对象,而且遵循了HttpSessionBindingListener域对象属性解绑和绑定监听器的命名规则。
HttpSessionAttributeListener事件监听器接口:
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionAttributeListener extends EventListener {
public void attributeAdded(HttpSessionBindingEvent se);
public void attributeRemoved(HttpSessionBindingEvent se);
public void attributeReplaced(HttpSessionBindingEvent se);
}
HttpSessionBindingEvent 事件对象:
package javax.servlet.http;
public class HttpSessionBindingEvent extends HttpSessionEvent {
private static final long serialVersionUID = 1L;
/* The name to which the object is being bound or unbound */
private final String name;
/* The object is being bound or unbound */
private final Object value;
public HttpSessionBindingEvent(HttpSession session, String name) {
super(session);
this.name = name;
this.value = null;
}
public HttpSessionBindingEvent(HttpSession session, String name,
Object value) {
super(session);
this.name = name;
this.value = value;
}
@Override
public HttpSession getSession() {
return super.getSession();
}
public String getName() {
return name;
}
public Object getValue() {
return this.value;
}
}
2.3.4、HttpSession中JavaBean对象对绑定和解绑的监听器
HttpSessionBindingListener监听器主要用来对HttpSession中JavaBean对象的绑定和解绑进行监听。在功能上,和HttpSessionAttributeListener监听器有点儿类似。区别在于:
- HttpSessionBindingListener是用来监听HttpSession中的JavaBean对象,而HttpSessionAttributeListener是用来监听域对象HttpSession的,具体是域对象HttpSession中的属性变化,即前者的事件源是JavaBean对象,而后者是域对象HttpSession;
- HttpSessionBindingListener监听器接口是由JavaBean对象来继承和实现的,且不需要在web.xml中进行配置,而而HttpSessionAttributeListener监听器需要专门的监听器类来继承和实现,且该监听器类需要在web.xml中配置(也可以使用注解)才能生效。
在HttpSessionBindingListener事件监听器接口中,定义了两个方法,其中valueBound()方法用来监听HttpSession中JavaBean对象的绑定事件,即指将JavaBean对象存放在session域对象的事件;valueUnbound()方法用来监听HttpSession中JavaBean对象解绑的事件,即将JavaBean对象从session域对象中删除的事件。这两个方法的参数都是HttpSessionBindingEvent,即事件对象,和HttpSessionAttributeListener监听器的事件对象使用同一个类表示。
HttpSessionBindingListener事件监听器接口:
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionBindingListener extends EventListener {
public void valueBound(HttpSessionBindingEvent event);
public void valueUnbound(HttpSessionBindingEvent event);
}
2.3.5、HttpSession中JavaBean对象对钝化和恢复的监听器
HttpSessionActivationListener监听器主要用来对HttpSession中JavaBean对象的钝化和恢复进行监听。在用法上,和HttpSessionBindingListener 监听器有点儿类似,首先是他们的事件源都是JavaBean对象,所以需要JavaBean对象实现HttpSessionActivationListener接口来实现,其次,这类监听器也不需要再web.xml中配置才生效。
JavaBean对象钝化指的是Tomcat正常关闭时,那么Session对象中的JavaBean对象会被钝化,数据会保存到Tomcat的work目录下;JavaBean对象恢复指的是再次打开Tomcat的时候恢复work目录下这些数据。
在HttpSessionActivationListener事件监听器接口中,定义了两个方法,其中sessionWillPassivate()方法用来监听HttpSession中JavaBean对象的钝化事件,即指Tomcat正常关闭时,将JavaBean对象存放会保存到Tomcat的work目录下的事件;sessionDidActivate()方法用来监听HttpSession中JavaBean对象恢复的事件,即指再次打开Tomcat的时候,恢复work目录下数据的事件。这两个方法的参数都是HttpSessionEvent,即事件对象,和HttpSessionIdListener、HttpSessionListener监听器的事件对象使用同一个类表示。
HttpSessionActivationListener 事件监听器接口:
package javax.servlet.http;
import java.util.EventListener;
public interface HttpSessionActivationListener extends EventListener {
public void sessionWillPassivate(HttpSessionEvent se);
public void sessionDidActivate(HttpSessionEvent se);
}
3、监听器使用示例
在Gitee中,我准备了一个完整的Listener示例的Demo,感兴趣的童鞋,可以使用,地址:https://gitee.com/hsh2015/servlet-learning/tree/master/servlet-listener。
在该示例中,我们把这篇文章提到的所有监听器都准备了示例,因为好多监听器的用法都是类似的,所以这里以Session相关的监听器为主来演示。
首先项目结构如下所示:
其中、context、request、session包分别对应了ServletContext、ServletRequest、HttpSession相关监听器,其中在session.bean子包下包含的是HttpSession的HttpSessionActivationListener和HttpSessionBindingListener的示例;controller包,存放了用于测试controller方法;WEB-INF/pages目录下,保存了一个测试使用的页面。
3.1、MyHttpSessionListener监听器示例
首先,我们演示MyHttpSessionListener监听器,因为在初始化HttpSession的时候,也可能会触发其他监听器,为了避免其他监听器干扰,@ServletComponentScan注解的包路径设置成:com.hsh.listener.session.other,即只扫描该目录下的监听器配置(@WebListener注解的类)。
在Application.class类中的配置如下:
//可以扫描到com.hsh.listener包下的监听器类
@ServletComponentScan(value = { "com.hsh.listener.session.other" })
@ComponentScan
@SpringBootApplication
public class ListenerApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ListenerApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ListenerApplication.class);
}
}
在IndexController.class测试类中添加如下方法:
@Controller
public class IndexController {
@RequestMapping("/index")
public String session(HttpServletRequest request, HttpServletResponse response){
return "SessionTest";
}
@RequestMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
session.invalidate();
System.out.println("Session对象被销毁了");
return "SessionTest";
}
//其他方法省略了
}
MyHttpSessionListener 监听器代码如下所示:
@WebListener
public class MyHttpSessionListener implements HttpSessionListener, HttpSessionIdListener{
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("MyHttpSessionListener-sessionCreated()方法,HttpSession初始化……");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("MyHttpSessionListener-sessionDestroyed()方法,HttpSession销毁……");
}
@Override
public void sessionIdChanged(HttpSessionEvent se, String oldSessionId) {
System.out.println("MyHttpSessionListener-sessionIdChanged()方法,HttpSessionID发生变化……");
}
}
访问http://localhost:8080/servlet-listener/index,控制台打印日志如下:
页面如下:
点击“销毁Session”按钮,实际上调用了http://localhost:8080/servlet-listener/logout,控制台打印日志如下:
销毁Session后,返回页面时,又创建了一个Session,所以又除非了一次初始化操作。
3.2、MyHttpSessionAttributeListener监听器示例
MyHttpSessionAttributeListener监听器代码如下:
@WebListener
public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("MyHttpSessionAttributeListener-attributeAdded()方法,HttpSession属性对象添加……");
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("MyHttpSessionAttributeListener-attributeRemoved()方法,HttpSession属性对象移除……");
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("MyHttpSessionAttributeListener-attributeReplaced()方法,HttpSession属性对象替换……");
}
}
在IndexController.class测试类中添加如下方法:
@RequestMapping("/testSessionAttribute")
public String testSessionAttribute(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
System.out.println("########## 添加 ##############");
session.setAttribute("username", "张三");
session.setAttribute("age", 15);
System.out.println("########### 移除 #############");
session.removeAttribute("username");
System.out.println("########## 替换 ##############");
session.setAttribute("age", 16);
return "SessionTest";
}
访问http://localhost:8080/servlet-listener/testSessionAttribute,控制台打印日志如下:
因为第一次请求会触发MyHttpSessionListener监听器的初始化方法,所以会打印日志。
3.3、MyUserOfBinding监听器示例
MyUserOfBinding监听器,监听的是JavaBean对象。这里把抽象出了一个MyUser对象,供HttpSessionBindingListener和HttpSessionActivationListener监听器公用。首先我们看HttpSessionBindingListener监听器对应的代码,首先实现了HttpSessionBindingListener接口,同时继承了MyUser类,代码如下:
MyUserOfBinding监听器代码:
public class MyUserOfBinding extends MyUser implements HttpSessionBindingListener {
private static final long serialVersionUID = 1L;
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("MyUserOfBinding-valueBound()方法,JavaBean对象绑定……");
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("MyUserOfBinding-valueUnbound()方法,JavaBean对象解绑……");
}
}
public class MyUser implements Serializable {
private static final long serialVersionUID = 1L;
private String uername;
private String password;
private String note;
//getter.setter方法省略了
}
在IndexController.class测试类中添加如下方法:
@RequestMapping("/testSessionAttribute")
public String testSessionAttribute(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
System.out.println("########## 添加 ##############");
session.setAttribute("username", "张三");
session.setAttribute("age", 15);
System.out.println("########### 移除 #############");
session.removeAttribute("username");
System.out.println("########## 替换 ##############");
session.setAttribute("age", 16);
return "SessionTest";
}
ListenerApplication类中@ServletComponentScan注解的包路径设置成:com.hsh.listener.session.bean,即只扫描该目录下的监听器配置(@WebListener注解的类),避免其他监听器干扰,其他和上面提到的ListenerApplication 代码一样,不再重复。
访问http://localhost:8080/servlet-listener/bindTest,控制台打印日志如下:
3.4、MyUserOfActivation监听器示例
HttpSessionActivationListener监听器和HttpSessionBindingListener监听器一样,都是监听JavaBean对象的,不过HttpSessionActivationListener监听的测试,需要配合Tomcat服务器启动和关闭来进行测试。因为通过独立服务器部署的时候,Application类上的注解@ServletComponentScan就会失效,为了避免其他监听器干扰,建议注释这些监听器的@WebListener注解。需要使用的代码如下:
MyUserOfActivation代码如如下:
MyUser 类和前面的代码完全一样。
public class MyUserOfActivation extends MyUser implements HttpSessionActivationListener {
private static final long serialVersionUID = 1L;
@Override
public void sessionWillPassivate(HttpSessionEvent se) {
System.out.println("MyUserOfActivation-sessionWillPassivate()方法,JavaBean对象钝化……");
}
@Override
public void sessionDidActivate(HttpSessionEvent se) {
System.out.println("MyUserOfActivation-sessionDidActivate()方法,JavaBean对象激活……");
}
}
在IndexController.class测试类中添加如下方法:
@RequestMapping("/activationTest")
public String activationTest(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
MyUserOfActivation user = new MyUserOfActivation();
user.setUername("user1");
session.setAttribute("user", user);
return "SessionTest";
}
演示流程:首先需要使用独立的Tomcat部署应用,然后访问http://localhost:8080/servlet-listener/activationTest,设置信息到Session中,然后关闭Tomcat,这个时候会出现JavaBean对象被钝化的日志,然后再启动Tomcat,又会出现JavaBean被激活的日志,如下所示:
3.5、其他
其他演示示例请参考Gitee,其中MyServletContextListener监听器,需要部署到独立的Tomcat上,通过启动和停止Tomcat来进行验证,其他的均可以通过url来进行。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68838.html