ApplicationContext的事件机制是观察者设计模式的实现,通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 的事件处理。如果容器中有一个 ApplicationListener Bean 每当 ApplicationContext 发布 ApplicationEvent时,ApplicationListener Bean将自动触发。
Spring的事件框架有如下两个重要成员。
》ApplicationEvent: 容器事件,必须由 ApplicationContext发布。
》ApplicationListener: 监听器,可有容器中的任何监听器Bean担任
实际上,Spring 的事件机制与所有的事件机制都基本类似,他们都需要 事件源, 事件 和事件监听器 组成。只是此处的事件源是ApplicationContext。
下图简单示范了ApplicationContext事件
下面的程序僵尸翻生Spring容器的事件程序 。程序先定义了一个ApplicationContext类,其对象就是一个Spring容器事件。代码如下:
import org.springframework.context.ApplicationEvent; public class EmailEvent extends ApplicationEvent{ private static final long serialVersionUID = -7056841418193254583L; private String address;
private String text;
public EmailEvent(Object source) {
super(source);
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
} }
上面的EmailEvent类继承了ApplicationContext类,除此之外,它就是一个普通的Java类。
容器的监听器必须实现ApplicationListener接口,实现该接口必须实现如下方法:
》onApplicationEvent(ApplicationEvent event):每当容器内发生任何事件时,此方法都被触发。
本例所用的监听器代码如下:
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener; public class EmailNotifier implements ApplicationListener<ApplicationEvent>{ //该方法会在容器发生事件时自动触发
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof EmailEvent){
//只处理EmailEvent,发送Email通知...
EmailEvent emailEvent = (EmailEvent)event;
System.out.println("需要发送的邮件的接收地址:"+emailEvent.getAddress());
System.out.println("需要发送邮件的邮件正文:"+emailEvent.getText());
}else{
//容器内置时间不做任何处理
System.out.println("容器本身事件: "+event);
}
} }
将监听器配置在容器中,配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 配置监听器 -->
<bean class="com.spring_example.event.EmailNotifier" />
</beans>
从上面的配置文件中可以看出,为Spring容器注册事件监听器,不需要像AWT编程那样采用代码进行编程,只要进行简单的配置即可。当我们在Spring配置了一个实现ApplicationListener的Bean。Springl容器就会把这个Bean当初容器的监听器。
当系统创建Spring容器,加载Spring容器时会自动触发容器事件,容器事件监听器可以监听到这些事件。除此之外,程序也可调用ApplicationContext的publishEvent方法来主动触发容器事件。如下主程序使用ApplicationContext的publishEvent来触发事件。
ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext.xml");
//创建一个ApplicationEvent对象
EmailEvent ele = new EmailEvent("Hello");
ele.setAddress("123456@163.com");
ele.setText("Hello World");
//主动触发容器事件
ac.publishEvent(ele);
上面的代码通过ApplicationContext对象的publishEvent主动触发该事件。运行上面的程序将看到如下执行结果。
容器本身事件: 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]
需要发送的邮件的接收地址:123456@163.com
需要发送邮件的邮件正文: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的这种事件模型其实就是标准的观察者设计模式。