监听器

作者: 仄青 | 来源:发表于2019-11-04 17:44 被阅读0次

    监听器

    本文包括:

    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文件中使用<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主要用来干什么?

            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 {
      

    相关文章

      网友评论

          本文标题:监听器

          本文链接:https://www.haomeiwen.com/subject/fdkdbctx.html