监听器
本文包括:
1、Listener简介
2、Servlet监听器
3、监听三个域对象创建和销毁的事件监听器
4、监听三个域对象的属性(Attribute)的变化的事件监听器
5、监听绑定到 HttpSession 域中的某个对象的状态的事件监听器
1、Listener简介
- Listener(监听器)就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
-
为了加深理解,自定义监听器来练练手,假设现在有个体重100的人要吃饭了,要监听他吃饭的动作,捕捉到了之后再打印它的体重,具体思路如下;
-
事件源类:
public class Person { private String name; private int weight;// 体重 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } }
-
监听器接口:
public interface PersonListener { public void personeating(PersonEvent event);// 监听方法,需要一个事件对象作为参数 }
-
事件类:
public class PersonEvent { private Object source;// 事件源 public Object getSource() { return source; } public void setSource(Object source) { this.source = source; } // 提供一个这样的构造方法:构造事件对象时,接收事件源(Person) public PersonEvent(Person person) { this.source = person; } }
-
在事件源中注册监听器
public class Person { private String name; private int weight;// 体重 private PersonListener listener; // 注册监听器 public void addPersonListener(PersonListener listener) { this.listener = listener; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } }
-
操作事件源----- 在事件源方法中,构造事件对象,参数为当前事件源(this),传递事件对象给监听器的监听方法:
public class Person { private String name; private int weight;// 体重 private PersonListener listener; // 注册监听器 public void addPersonListener(PersonListener listener) { this.listener = listener; } // 吃饭 public void eat() { // 体重增加 weight += 5; // 调用监听器监听方法 if (listener != null) { // 监听器存在 // 创建事件对象 --- 通过事件对象可以获得事件源 PersonEvent event = new PersonEvent(this); listener.personeating(event); } } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } }
-
测试
public class PersonTest { public static void main(String[] args) { // 步骤一 创建事件源 Person person = new Person(); person.setName("小明"); person.setWeight(100); // 步骤二 给事件源注册监听器(该监听器由匿名内部类创建) person.addPersonListener(new PersonListener() { @Override public void personeating(PersonEvent event) { System.out.println("监听到了,人正在吃饭!"); // 在监听方法中可以获得事件源对象,进而可以操作事件源对象 Person person = (Person) event.getSource(); System.out.println(person.getName()); System.out.println(person.getWeight()); } }); // 步骤三 操作事件源 person.eat();// 结果监听方法被调用 } }
2、Servlet监听器
-
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源是三个域对象,分别为:
- ServletContext
- HttpSession
- ServletRequest
-
Servlet规范针对这三个域对象上的操作,又把这多种类型的监听器划分为三种类型:
- 监听三个域对象的创建和销毁的事件监听器
- 监听三个域对象的属性(Attribute)的增加和删除的事件监听器
- 监听绑定到 HttpSession 域中的某个对象的状态的事件监听器。(查看API文档)
-
编写 Servlet 监听器:
- 和编写其它事件监听器一样,编写Servlet监听器也需要实现一个特定的接口,并针对相应动作覆盖接口中的相应方法。
- 和其它事件监听器略有不同的是,Servlet监听器的注册不是直接注册在事件源上,而是由WEB容器负责注册,开发人员只需在web.xml文件中使用<listener>标签配置好监听器,web容器就会自动把监听器注册到事件源中。
- 一个 web.xml 文件中可以配置多个 Servlet 事件监听器,web 服务器按照它们在 web.xml 文件中的注册顺序来加载和注册这些 Serlvet 事件监听器。配置代码如下所示:
<!-- 对监听器进行注册 --> <!-- 监听器和Servlet、Filter不同,不需要url配置,监听器执行不是由用户访问的,监听器 是由事件源自动调用的 --> <listener> <listener-class>cn.itcast.servlet.listener.MyServletContextListener</listener-class> </listener>
3、监听三个域对象创建和销毁的事件监听器
3.1、ServletContextListener
-
ServletContextListener 接口用于监听 ServletContext 对象的创建和销毁事件。
-
当 ServletContext 对象被创建时,调用接口中的方法:
ServletContextListener.contextInitialized (ServletContextEvent sce)
-
当 ServletContext 对象被销毁时,调用接口中的方法:
ServletContextListener.contextDestroyed(ServletContextEvent sce)
-
-
ServletContext域对象何时创建和销毁:
- 创建:服务器启动时,针对每一个web应用创建Servletcontext
- 销毁:服务器关闭前,先关闭代表每一个web应用的ServletContext
-
ServletContext主要用来干什么?
-
保存全局应用数据对象
- 在服务器启动时,对一些对象进行初始化,并且将对象保存ServletContext数据范围内 —— 实现全局数据
- 例如:创建数据库连接池
-
加载框架配置文件
- Spring框架(配置文件随服务器启动加载) org.springframework.web.context.ContextLoaderListener
-
实现任务调度(定时器),启动定时程序
-
java.util.Timer:一种线程设施,用于安排以后在后台线程中执行的任务,可安排任务执行一次,或者定期重复执行。
-
Timer提供了启动定时任务方法 Timer.schedule(),其中有两种方法需要记住:
-
在指定的一个时间时启动定时器,定期执行一次
Timer.schedule(TimerTask task, Date firstTime, long period)
-
在当前时间延迟多少毫秒后启动定时器,定期执行一次
Timer.schedule(TimerTask task, long delay, long period)
-
-
停止定时器,取消任务
Timer.cancel()
-
-
-
demo:
package cn.itcast.servlet.listener; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; /** * 自定义 Context监听器 * * @author seawind * */ public class MyServletContextListener implements ServletContextListener { @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("监听ServletContext对象销毁了..."); } @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("监听ServletContext对象创建了..."); // 获得事件源 ServletContext servletContext = sce.getServletContext(); // 向ServletContext 中保存数据 // 启动定时器 final Timer timer = new Timer(); // 启动定时任务 // timer.schedule(new TimerTask() { // @Override // // 这就是一个线程 // public void run() { // System.out.println("定时器执行了..."); // } // }, 0, 3000); // 马上启动 每隔3秒重复执行 // 指定时间启动定时器 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); try { Date first = dateFormat.parse("2012-08-07 10:42:00"); timer.schedule(new TimerTask() { int i; @Override public void run() { i++; System.out.println("从10点40分开始启动程序,每隔3秒重复执行"); if (i == 10) { timer.cancel();// 取消定时器任务 } } }, first, 3000); } catch (ParseException e) { e.printStackTrace(); } } }
3.2、HttpSessionListener
-
HttpSessionListener接口用于监听HttpSession的创建和销毁
-
创建一个Session时,接口中的该方法将会被调用:
HttpSessionListener.sessionCreated(HttpSessionEvent se)
-
销毁一个Session时,接口中的该方法将会被调用:
HttpSessionListener.sessionDestroyed (HttpSessionEvent se)
-
-
Session域对象创建和销毁:
- 创建:浏览器访问服务器时,服务器为每个浏览器创建不同的 session 对象,服务器创建session
- 销毁:如果用户的session的30分钟没有使用,session就会过期,我们在Tomcat的web.xml里面也可以配置session过期时间。
-
demo:
package cn.itcast.servlet.listener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent se) { // 通过事件对象获得session 的id System.out.println("session被创建了"); HttpSession session = se.getSession(); System.out.println("id:" + session.getId()); } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("session被销毁了"); HttpSession session = se.getSession(); System.out.println("id:" + session.getId()); } }
关于HttpSession的生命周期、具体描述详见:JSP 会话管理
3.3、ServletRequestListener(很少用)
- ServletRequestListener 接口用于监听ServletRequest 对象的创建和销毁:
- ServletRequest对象被创建时,监听器的requestInitialized方法将会被调用。
- ServletRequest对象被销毁时,监听器的requestDestroyed方法将会被调用。
- ServletRequest域对象创建和销毁的时机:
- 创建:用户每一次访问,都会创建一个reqeust
- 销毁:当前访问结束,request对象就会销毁
- 这个监听器最需要注意的:
- 使用forward ---- request创建销毁一次 (因为转发本质是一次请求)
- 使用sendRedirect ---- request创建销毁两次 (因为重定向本质是两次请求)
关于ServletRequest详见:http://www.jianshu.com/p/7e2e3fd58e91
-
-
springboot 配置监听器: 1.添加@WebListener注解 @WebListener public class MyHttpSessionListener implements HttpSessionListener { 2.添加@ComponentScan,@ServletComponentScan @ComponentScan("com.springboot.demo.*") @ServletComponentScan(basePackages = "com.springboot.demo.*") public class DemoApplication {
-
网友评论