监听器

监听器

本文包括:

1、Listener简介

2、Servlet监听器

3、监听三个域对象创建和销毁的事件监听器

4、监听三个域对象的属性(Attribute)的变化的事件监听器

5、监听绑定到 HttpSession 域中的某个对象的状态的事件监听器

1、Listener简介

  • Listener(监听器)就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
  • 为了加深理解,自定义监听器来练练手,假设现在有个体重100的人要吃饭了,要监听他吃饭的动作,捕捉到了之后再打印它的体重,具体思路如下;

    1. 事件源类:

      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;
           }
       }
      
    2. 监听器接口:

       public interface PersonListener {
           public void personeating(PersonEvent event);// 监听方法,需要一个事件对象作为参数
       }
      
    3. 事件类:

       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;
           }
       
       }
      
    4. 在事件源中注册监听器

       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;
           }
       }
      
    5. 操作事件源----- 在事件源方法中,构造事件对象,参数为当前事件源(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;
           }
       }
      
    6. 测试

      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文件中使用标签配置好监听器,web容器就会自动把监听器注册到事件源中。
        • 一个 web.xml 文件中可以配置多个 Servlet 事件监听器,web 服务器按照它们在 web.xml 文件中的注册顺序来加载和注册这些 Serlvet 事件监听器。配置代码如下所示:
        
          
          
              cn.itcast.servlet.listener.MyServletContextListener
          
        

        3、监听三个域对象创建和销毁的事件监听器

        3.1、ServletContextListener

        • ServletContextListener 接口用于监听 ServletContext 对象的创建和销毁事件。

          • 当 ServletContext 对象被创建时,调用接口中的方法:

              ServletContextListener.contextInitialized (ServletContextEvent sce)
            
          • 当 ServletContext 对象被销毁时,调用接口中的方法:

              ServletContextListener.contextDestroyed(ServletContextEvent sce)
            
        • ServletContext域对象何时创建和销毁:

          • 创建:服务器启动时,针对每一个web应用创建Servletcontext
          • 销毁:服务器关闭前,先关闭代表每一个web应用的ServletContext
        • ServletContext主要用来干什么?

          1. 保存全局应用数据对象

            • 在服务器启动时,对一些对象进行初始化,并且将对象保存ServletContext数据范围内 —— 实现全局数据
            • 例如:创建数据库连接池
          2. 加载框架配置文件

            • Spring框架(配置文件随服务器启动加载) org.springframework.web.context.ContextLoaderListener
          3. 实现任务调度(定时器),启动定时程序

            • java.util.Timer:一种线程设施,用于安排以后在后台线程中执行的任务,可安排任务执行一次,或者定期重复执行。

            • Timer提供了启动定时任务方法 Timer.schedule(),其中有两种方法需要记住:

              1. 在指定的一个时间时启动定时器,定期执行一次

                  Timer.schedule(TimerTask task, Date firstTime, long period)  
                
              2. 在当前时间延迟多少毫秒后启动定时器,定期执行一次

                  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 {
    

你可能感兴趣的:(监听器)