Spring ApplicationContext的事件机制

  ApplicationContext的事件机制是观察者设计模式的实现,通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 的事件处理。如果容器中有一个 ApplicationListener Bean 每当 ApplicationContext 发布 ApplicationEvent时,ApplicationListener Bean将自动触发。

  Spring的事件框架有如下两个重要成员。

  》ApplicationEvent: 容器事件,必须由 ApplicationContext发布。

  》ApplicationListener: 监听器,可有容器中的任何监听器Bean担任

  实际上,Spring 的事件机制与所有的事件机制都基本类似,他们都需要 事件源事件事件监听器 组成。只是此处的事件源是ApplicationContext。

  下图简单示范了ApplicationContext事件

  

 

  下面的程序僵尸翻生Spring容器的事件程序 。程序先定义了一个ApplicationContext类,其对象就是一个Spring容器事件。代码如下:

 1 import org.springframework.context.ApplicationEvent;
 2 
 3 public class EmailEvent extends ApplicationEvent{
 4 
 5     private static final long serialVersionUID = -7056841418193254583L;
 6 
 7     private String address;
 8     private String text;
 9     public EmailEvent(Object source) {
10         super(source);
11     }
12     public String getAddress() {
13         return address;
14     }
15     public void setAddress(String address) {
16         this.address = address;
17     }
18     public String getText() {
19         return text;
20     }
21     public void setText(String text) {
22         this.text = text;
23     }
24     
25 }

  上面的EmailEvent类继承了ApplicationContext类,除此之外,它就是一个普通的Java类。

  容器的监听器必须实现ApplicationListener接口,实现该接口必须实现如下方法:

  》onApplicationEvent(ApplicationEvent event):每当容器内发生任何事件时,此方法都被触发。

  本例所用的监听器代码如下:

 1 import org.springframework.context.ApplicationEvent;
 2 import org.springframework.context.ApplicationListener;
 3 
 4 public class EmailNotifier implements ApplicationListener<ApplicationEvent>{
 5 
 6     //该方法会在容器发生事件时自动触发
 7     public void onApplicationEvent(ApplicationEvent event) {
 8         if(event instanceof EmailEvent){
 9             //只处理EmailEvent,发送Email通知...
10             EmailEvent emailEvent = (EmailEvent)event;
11             System.out.println("需要发送的邮件的接收地址:"+emailEvent.getAddress());
12             System.out.println("需要发送邮件的邮件正文:"+emailEvent.getText());
13         }else{
14             //容器内置时间不做任何处理
15             System.out.println("容器本身事件: "+event);
16         }
17     }
18 
19 }

  将监听器配置在容器中,配置文件如下:

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans
3     xmlns="http://www.springframework.org/schema/beans"
4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5     xmlns:p="http://www.springframework.org/schema/p"
6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
7     <!-- 配置监听器 -->
8     <bean class="com.spring_example.event.EmailNotifier" />
9 </beans>

  从上面的配置文件中可以看出,为Spring容器注册事件监听器,不需要像AWT编程那样采用代码进行编程,只要进行简单的配置即可。当我们在Spring配置了一个实现ApplicationListener的Bean。Springl容器就会把这个Bean当初容器的监听器。

  当系统创建Spring容器,加载Spring容器时会自动触发容器事件,容器事件监听器可以监听到这些事件。除此之外,程序也可调用ApplicationContext的publishEvent方法来主动触发容器事件。如下主程序使用ApplicationContext的publishEvent来触发事件。

1         ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
2         //创建一个ApplicationEvent对象
3         EmailEvent ele = new EmailEvent("Hello");
4         ele.setAddress("123456@163.com");
5         ele.setText("Hello World");
6         //主动触发容器事件
7         ac.publishEvent(ele);

  上面的代码通过ApplicationContext对象的publishEvent主动触发该事件。运行上面的程序将看到如下执行结果。

1 容器本身事件: org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@141b571: startup date [Fri Sep 13 10:16:01 CST 2013]; root of context hierarchy]
2 需要发送的邮件的接收地址:123456@163.com
3 需要发送邮件的邮件正文:Hello World

  从上面的执行结果可以看出,监听器不仅监听到程序所触发的事件,也监听到容器内置的事件。实际上,如果开发者需要在Spring容器初始化,销毁时回调自定义方法,就可以通过上面的监听器来实现。

  如果Bean想发布事件,则Bean必须获得其容器的引用。如果程序中没有直接获取容器的引用,则应该让Bean实现ApplicationContextAware 或 BeanFactoryAware接口,从而可以获得容器的引用。

  Spring提供如下几个内置事件:

  》ContextRefreshEvent: ApplicationContext容器初始化或刷新触发该事件。此处的初始化是指,所有Bean 被成功装载,后处理Bean被检测并激发,所有Singleton Bean被预实例化,ApplicationContext容器已就绪可用。

  》ContextStartedEvent: 当使用ConfigurableApplicationContext(ApplicationContext的子接口)接口的start()方法启动ApplicationContext容器时触发该事件。容器管理生命周期的Bean实例将获得一个指定的启动信号,这在经常需要停止后重新启动的场合比较常见。

  》ContextClosedEvent:当使用ConfigurableApplicationContext接口的close()方法关闭ApplicationContext容器时触发该事件。

  》ContextStoppedEvent:当使用ConfigurableApplicationContext接口的stop()方法使ApplicationContext停止时触发该事件。此处的“停止”意味着容器管理生命周期的Bean实例将获得一个指定的停止信号,被停止的Spring容器可在此调用start()方法重新启动。

  》RequestHandledEvent:Web相关的事件,只能运用于使用DispatcherServlet的Web运用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。

  Spring的这种事件模型其实就是标准的观察者设计模式。

 

posted on 2013-09-13 10:34  Arts&Crafts  阅读(7135)  评论(0编辑  收藏  举报

导航