每天开心一点

Java 反射(reflection)/注释(Annotation)/监听器(Listener)/装饰器(wrapper)/过滤器(Filter)(三)

2018-01-10 08:59:00    六月    1312    来源: https://www.2cto.com/kf/201708/665618.html

三 监听器(Listener)

3.1 作用

监听器是一个专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动。监听器其实就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法立即被执行。

3.2 实现原理

3.2.1 Java Listener

可以按照严格的事件处理模型来设计一个对象,这个对象就可以被别的对象监听,事件处理模型涉及到三个 组件:事件源、事件对象、事件监听器。Listener的实现基于回调函数实现。


3.2.2 JavaWeb Listener

listener是通过观察者设计模式进行实现的。观察者模式又叫发布订阅模式或者监听器模式。在该模式中有两个角色:观察者和被观察者(通常也叫做主题)。观察者在主题里面注册自己感兴趣的事件,当这个事件发生时,主题会通过回调接口的方式通知观察者。

对于JavaWeb里面的监听器,Servlet规范定义了一些列的Listener接口类,通过接口类的方式将事件暴露给应用程序,应用程序如果想监听其感兴趣的事件,那么不必去直接注册对应的事件,而是编写自己的listener实现相应的接口类,并将自己的listener注册到servlet容器。当程序关心的事件发生时,servlet容器会通知listener,回调listener里面的方法。这里自定义的listener就是观察者,servlet容器就是主题。

在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext,HttpSession和ServletRequest这三个域对象,Servlet规范针对这三个对象上的操作,又把多种类型的监听器划分为三种类型:

1.监听域对象自身的创建和销毁的事件监听器。

2.监听域对象中的属性的增加和删除的事件监听器。

3.监听绑定到HttpSession域中的某个对象的状态的事件监听器。

3.3 应用场景

应用在桌面开发和JavaWeb中。

3.4 范例

Java桌面开发中使用Listener监听消息示例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
packageme.gacl.listener.demo;
  
importjava.awt.Frame;
importjava.awt.event.WindowEvent;
importjava.awt.event.WindowListener;
  
publicclassDemo1 {
  
    /**
     *java的事件监听机制
     *1、事件监听涉及到三个组件:事件源、事件对象、事件监听器
     *2、当事件源上发生某一个动作时,它会调用事件监听器的一个方法,并在调用该方法时把事件对象传递进去,
     *    开发人员在监听器中通过事件对象,就可以拿到事件源,从而对事件源进行操作。
     */
    publicstaticvoidmain(String[] args) {
         
        Frame f =newFrame();
        f.setSize(400,400);
        f.setVisible(true);
         
        //注册事件监听器
        f.addWindowListener(newWindowListener(){
  
            publicvoidwindowActivated(WindowEvent e) {
                 
            }
  
            publicvoidwindowClosed(WindowEvent e) {
                 
            }
  
            /**
             * 当window窗体关闭时就会WindowListener这个监听器监听到,
             * 监听器就会调用windowClosing方法处理window窗体关闭时的动作
             */
            publicvoidwindowClosing(WindowEvent e) {
                //通过事件对象e来获取事件源对象
                Frame f = (Frame) e.getSource();
                System.out.println(f+"窗体正在关闭");
                f.dispose();
            }
  
            publicvoidwindowDeactivated(WindowEvent e) {
                 
            }
  
            publicvoidwindowDeiconified(WindowEvent e) {
                 
            }
  
            publicvoidwindowIconified(WindowEvent e) {
                 
            }
  
            publicvoidwindowOpened(WindowEvent e) {
                 
            }
        });
    }
}

我们平时做开发的时候,我们是写监听器去监听其他对象,那么我们如果想设计一个对象,让这个对象可以被别的对象监听又该怎么做呢,可以按照严格的事件处理模型来设计一个对象,这个对象就可以被别的对象监听,事件处理模型涉及到三个组件:事件源、事件对象、事件监听器。

下面我们来按照事件处理模型来设计一个Person对象 具体代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
packageme.gacl.observer;
  
/**
* @ClassName: Person(事件源)
* @Description: 设计一个Person类作为事件源,这个类的对象的行为(比如吃饭、跑步)可以被其他的对象监听
* @author: 孤傲苍狼
* @date: 2014-9-9 下午9:26:06
*
*/ 
publicclassPerson {
    /**
    * @Field: listener
    *          在Person类中定义一个PersonListener变量来记住传递进来的监听器
    */
    privatePersonListener listener;
  
    /**
    * @Method: eat
    * @Description: 设计Person的行为:吃
    * @Anthor:孤傲苍狼
    *
    */
    publicvoideat() {
        if(listener !=null) {
            /**
             * 调用监听器的doeat方法监听Person类对象eat(吃)这个动作,将事件对象Event传递给doeat方法,
             * 事件对象封装了事件源,new Event(this)中的this代表的就是事件源
             */
            listener.doeat(newEvent(this));
        }
    }
  
    /**
    * @Method: run
    * @Description: 设计Person的行为:跑
    * @Anthor:孤傲苍狼
    *
    */
    publicvoidrun() {
        if(listener !=null) {
            /**
             * 调用监听器的dorun方法监听Person类对象run(跑)这个动作,将事件对象Event传递给doeat方法,
             * 事件对象封装了事件源,new Event(this)中的this代表的就是事件源
             */
            listener.dorun(newEvent(this));
        }
    }
  
    /**
    * @Method: registerListener
    * @Description: 这个方法是用来注册对Person类对象的行为进行监听的监听器
    * @Anthor:孤傲苍狼
    *
    * @param listener
    */
    publicvoidregisterListener(PersonListener listener) {
        this.listener = listener;
    }
}
  
/**
* @ClassName: PersonListener(事件监听器)
* @Description: 设计Person类(事件源)的监听器接口
* @author: 孤傲苍狼
* @date: 2014-9-9 下午9:28:06
*
*/
interfacePersonListener {
  
    /**
    * @Method: doeat
    * @Description: 这个方法是用来监听Person对象eat(吃)这个行为动作,
    *                 当实现类实现doeat方法时就可以监听到Person类对象eat(吃)这个动作
    * @Anthor:孤傲苍狼
    *
    * @param e
    */
    voiddoeat(Event e);
  
    /**
    * @Method: dorun
    * @Description: 这个方法是用来监听Person对象run(跑)这个行为动作,
    *                 当实现类实现dorun方法时就可以监听到Person类对象run(跑)这个动作
    * @Anthor:孤傲苍狼
    *
    * @param e
    */
    voiddorun(Event e);
  
}
  
/**
* @ClassName: Event(事件对象)
* @Description:设计事件类,用来封装事件源
* @author: 孤傲苍狼
* @date: 2014-9-9 下午9:37:56
*
*/
classEvent {
  
    /**
    * @Field: source
    *          事件源(Person就是事件源)
    */
    privatePerson source;
  
    publicEvent() {
         
    }
  
    publicEvent(Person source) {
        this.source = source;
    }
  
    publicPerson getSource() {
        returnsource;
    }
  
    publicvoidsetSource(Person source) {
        this.source = source;
    }
}

经过这样的设计之后,Peron类的对象就是可以被其他对象监听了。测试代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
packageme.gacl.observer;
  
publicclassPersonTest {
  
    /**
     * @Method: main
     * @Description: 测试Person类
     * @Anthor:孤傲苍狼
     *
     * @param args
     */
    publicstaticvoidmain(String[] args) {
        //
        Person p =newPerson();
        //注册监听p对象行为的监听器
        p.registerListener(newPersonListener() {
            //监听p吃东西这个行为
            publicvoiddoeat(Event e) {
                Person p = e.getSource();
                System.out.println(p +"在吃东西");
            }
            //监听p跑步这个行为
            publicvoiddorun(Event e) {
                Person p = e.getSource();
                System.out.println(p +"在跑步");
            }
        });
        //p在吃东西
        p.eat();
        //p在跑步
        p.run();
    }
}

JavaWeb

监听ServletContext域对象的创建和销毁

ServletContextListener接口用于监听ServletContext对象的 创建和销毁事件。实现了ServletContextListener接口的类都可以对ServletContext对象的创建和销毁进行监听。

ServletContext对象被创建时,激发contextInitialized (ServletContextEvent sce)方法。

当ServletContext对象被销毁时,激发contextDestroyed(ServletContextEvent sce)方法。

ServletContext域对象创建和销毁时机:

创建:服务器启动针对每一个Web应用创建ServletContext

销毁:服务器关闭前先关闭代表每一个web应用的ServletContext

范例:编写一个MyServletContextListener类,实现ServletContextListener接口,监听ServletContext对象的创建和销毁

1、编写监听器,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
packageme.gacl.web.listener;
  
importjavax.servlet.ServletContextEvent;
importjavax.servlet.ServletContextListener;
  
/**
* @ClassName: MyServletContextListener
* @Description: MyServletContextListener类实现了ServletContextListener接口,
*                 因此可以对ServletContext对象的创建和销毁这两个动作进行监听。
* @author: 孤傲苍狼
* @date: 2014-9-9 下午10:26:16
*
*/
publicclassMyServletContextListenerimplementsServletContextListener {
  
    @Override
    publicvoidcontextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext对象创建");
    }
  
    @Override
    publicvoidcontextDestroyed(ServletContextEvent sce) {
        System.out.println("ServletContext对象销毁");
    }
}

2、在web.xml文件中注册监听器

我们在上面的中讲到,要想监听事件源,那么必须将监听器注册到事件源上才能够实现对事件源的行为动作进行监听,在JavaWeb中,监听的注册是在web.xml文件中进行配置的,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--?xml version="1.0"encoding="UTF-8"?-->
    https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name>   
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
   
  <!-- 注册针对ServletContext对象进行监听的监听器 -->
  <listener>
      <description>ServletContextListener监听器</description>
      <!--实现了ServletContextListener接口的监听器类 -->
      <listener-class>me.gacl.web.listener.MyServletContextListener</listener-class>
  </listener>
   
</web-app>

经过这两个步骤,我们就完成了监听器的编写和注册,Web服务器在启动时,就会自动把在web.xml中配置的监听器注册到ServletContext对象上,这样开发好的MyServletContextListener监听器就可以对ServletContext对象进行监听了。 转载:https://www.cnblogs.com/xdp-gacl/p/3961929.html