目录
- 什么是监听器
- 为什么要使用监听器
- 监听器组件
- 实际操作——模拟监听器
- 事件对象
- 监听器
- 事件源
- 测试
- Servlet监听器
- 监听对象的创建和销毁
- 监听对象属性的变化
- 监听session对象的变化
什么是监听器
监听器的实质还是一段程序。是通过类实现某个接口来对另一个类的方法或者属性变化时产生监听的效果。好比你在超市购物的时候监控后台能看到你买了什么东西一个道理。
为什么要使用监听器
监听器最大的好处就是统计网站访问人数。例如廖大哥的官方网站就运用到了监听器来统计访问人数。
监听器组件
监听器一共有三大组件:事件源,事件对象以及事件监听器。那么我们在编写程序的时候就需要把这三个对象全都表示出来。
当事件源发生变化的时候,就会把事件对象传到事件监听器中然后去调用时间监听器。然后我们就可以在事件监听器中通过事件对象去操作事件源。
实际操作——模拟监听器
事件对象
package net.zxy.object;
import net.zxy.source.Person;
public class Event {
private Person person;
public Event() {
}
public Event(Person person) {
this.person = person;
}
public Person getPerson() {
return person;
}
}
监听器
监听器会定义成接口,然后把事件对象当作参数传递到方法中。例如:
package net.zxy.listener;
import net.zxy.object.Event;
public interface PersonListener {
void doEat(Event event);
void doSleep(Event event);
}
事件源
package net.zxy.source;
import net.zxy.listener.PersonListener;
import net.zxy.object.Event;
public class Person {
// 定义一个监听器对象
private PersonListener personListener;
// 在事件源中定义两个方法,用来触发监听器中的方法
public void eat(){
personListener.doEat(new Event(this));
}
public void sleep(){
personListener.doSleep(new Event(this));
}
// 注册监听器,把监听器对象传进来
public void registerListener(PersonListener personListener){
this.personListener=personListener;
}
}
测试
import net.zxy.listener.PersonListener;
import net.zxy.source.Person;
public class test {
public static void main(String[] args) {
Person person=new Person();
person.registerListener(new PersonListener() {
public void doEat(net.zxy.object.Event event) {
Person person1=event.getPerson();
System.out.println(person1+"正在吃饭呢");
}
public void doSleep(net.zxy.object.Event event) {
Person person1=event.getPerson();
System.out.println(person1+"正在睡觉呢");
}
});
person.eat();
}
}
Servlet监听器
同样,在Servlet规范中也定义了多种类型的监听器,它们用于监听的事件源分别是ServletContext,HttpSession和ServletRequest这三个对象。
和其他的监听器不同的是,servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责,开发人员只需要在web.xml中使用<listener>
标签配置好监听器。
监听对象的创建和销毁
ServletContextListener,HttpSessionListener和ServletRequestListener分别监控着Session、Context、Request对象的创建和销毁。
测试
public class Listener1 implements ServletContextListener,
HttpSessionListener, ServletRequestListener {
// Public constructor is required by servlet spec
public Listener1() {
}
public void contextInitialized(ServletContextEvent sce) {
System.out.println("容器创建了");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("容器销毁了");
}
public void sessionCreated(HttpSessionEvent se) {
System.out.println("Session创建了");
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("Session销毁了");
}
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
}
}
监听器监听到ServletContext的初始化了,Session的创建和ServletContext的销毁。(服务器停掉,不代表Session就被销毁了。Session的创建是在内存中的,所以没看到Session被销毁了)
监听对象属性的变化
ServletContextAttributeListener、HttpSessionAttributeListener、ServletRequestAttributeListener分别监听着Context、Session、Request对象属性的变化
这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同。
测试
为了方便,这儿就只测试Context对象就行了,其他的差不多一个道理
public class Listener1 implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("Context对象增加了属性");
}
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("Context对象删除了属性");
}
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("Context对象替换了属性");
}
}
用于测试的Servlet方法
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.setAttribute("aa", "123");
context.setAttribute("aa", "234");
context.removeAttribute("aa");
}
监听session对象的变化
除了上面的6种Listener,还有两种Linstener监听Session内的对象,分别是HttpSessionBindingListener和HttpSessionActivationListener,实现这两个接口并不需要在web.xml文件中注册
- 实现HttpSessionBindingListener接口,JavaBean 对象可以感知自己被绑定到 Session 中和从 Session 中删除的事件【和HttpSessionAttributeListener的作用是差不多的】
- 实现HttpSessionActivationListener接口,JavaBean 对象可以感知自己被活化和钝化的事件(当服务器关闭时,会将Session的内容保存在硬盘上【钝化】,当服务器开启时,会将Session的内容在硬盘式重新加载【活化】) 。。
想要测试出Session的硬化和钝化,需要修改Tomcat的配置的。在META-INF下的context.xml文件中添加下面的代码:
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="zxy"/>
</Manager>
</Context>
测试
/*
* 由于涉及到了将内存的Session钝化到硬盘和用硬盘活化到内存中,所以需要实现Serializable接口
*
* 该监听器是不需要在web.xml文件中配置的。但监听器要在事件源上实现接口
* 也就是说,直接用一个类实现HttpSessionBindingListener和HttpSessionActivationListener接口是监听不到Session内对象的变化的。
* 因为它们是感知自己在Session中的变化!
* */
public class User implements HttpSessionBindingListener,HttpSessionActivationListener,Serializable {
private String username ;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {
HttpSession httpSession = httpSessionEvent.getSession();
System.out.println("钝化了");
}
@Override
public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
HttpSession httpSession = httpSessionEvent.getSession();
System.out.println("活化了");
}
@Override
public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("绑定了对象");
}
@Override
public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("解除了对象");
}
}
User user = new User();
request.getSession().setAttribute("aaa", user);
request.getSession().removeAttribute("aaa");