这篇博客主要给大家介绍ApplicationContext的另外一个核心功能:事件机制。
使用事件机制可以解耦代码,观察者与被观察者可以分开开发,中间只有事件作为联系,不用关心另一方如何实现。观察者可以有多个,所以对于同一个事件可以有多种不同的处理方式,不过要确保不依赖处理的顺序。使用事件后,观察者可以单独开发,对主流程没有任何影响,可以简化主流程的开发。
事件可以用于各种场景的消息通知,比如系统收到停机指令后,可以发出停机事件,这样相关的子系统就可以进行停机前的各种处理。那么 Spring 中的事件是如何实现的呢?
ApplicationContext中事件处理是由ApplicationEvent类和ApplicationListener接口来提供的。如果一个Bean实现了ApplicationListener接口,并且已经发布到容器中去,每次ApplicationContext发布一个ApplicationEvent事件,这个Bean就会接到通知。Spring事件机制是观察者模式的实现。
ContextRefreshEvent,当ApplicationContext容器初始化完成或者被刷新的时候,就会发布该事件。比如调用ConfigurableApplicationContext接口中的refresh()方法。此处的容器初始化指的是所有的Bean都被成功装载,后处理(post-processor)Bean被检测到并且激活,所有单例Bean都被预实例化,ApplicationContext容器已经可以使用。只要上下文没有被关闭,刷新可以被多次触发。XMLWebApplicationContext支持热刷新,GenericApplicationContext不支持热刷新。
ContextStartedEvent,当ApplicationContext启动的时候发布事件,即调用ConfigurableApplicationContext接口的start方法的时候。这里的启动是指,所有的被容器管理生命周期的Bean接受到一个明确的启动信号。在经常需要停止后重新启动的场合比较适用。
ContextStoppedEvent,当ApplicationContext容器停止的时候发布事件,即调用ConfigurableApplicationContext的close方法的时候。这里的停止是指,所有被容器管理生命周期的Bean接到一个明确的停止信号。
ContextClosedEvent,当ApplicationContext关闭的时候发布事件,即调用ConfigurableApplicationContext的close方法的时候,关闭指的是所有的单例Bean都被销毁。关闭上下后,不能重新刷新或者重新启动。
RequestHandledEvent,只能用于DispatcherServlet的web应用,Spring处理用户请求结束后,系统会触发该事件。
1.定义自己的监听事件
package com.test.eventListener;
import org.springframework.context.ApplicationEvent;
public class StudentAddEvent extends ApplicationEvent {
private static final long serialVersionUID = 20L;
/**
* 学生姓名
*/
private String name;
/**
* @param source
*/
public StudentAddEvent(Object source, String name) {
super(source);
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.定义自己的监听器(负责处理自己的监听事件)
package com.test.eventListener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class StudentAddListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
// 1.判断是否是增加学生对象的事件
if (!(event instanceof StudentAddEvent)) {
return;
}
// 2.是增加学生事件的对象,进行逻辑处理,比如记日志、积分等
StudentAddEvent studentAddEvent = (StudentAddEvent) event;
System.out.println("增加了学生:" + studentAddEvent.getName());
}
}
3.定义一个bean触发监听事件
package com.test.eventListener;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class StudentAddBean implements ApplicationContextAware {
/**
* 定义Spring上下文对象
*/
private ApplicationContext applicationContext = null;
/*
* (non-Javadoc)
*
* @see
* org.springframework.context.ApplicationContextAware#setApplicationContext
* (org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 增加一个学生
*
* @param studentName
*/
public void addStudent(String studentName) {
// 1.构造一个增加学生的事件
StudentAddEvent aStudentEvent = new StudentAddEvent(
applicationContext, studentName);
// 2.触发增加学生事件
applicationContext.publishEvent(aStudentEvent);
}
}
4.测试
package com.test.eventListener;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class EventListenerTest {
public static void main(String[] args) {
String[] xmlConfig = new String[] { "spring/spring.xml" };
// 使用ApplicationContext来初始化系统
ApplicationContext context = new ClassPathXmlApplicationContext(xmlConfig);
StudentAddBean studentBean = (StudentAddBean) context.getBean("studentAddBean");
studentBean.addStudent("张三");
studentBean.addStudent("李四");
}
}
上面就是事件的简单例子。
那我们来看一下事件机制在spring里是怎么实现的。
ApplicationEvent:事件抽象类
public abstract class ApplicationEvent extends EventObject {
private long timestamp;
public ApplicationEvent(Object source) {
super(source);
timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
}
ApplicationListener :事件监听接口
public interface ApplicationListener extends EventListener {
//处理事件
void onApplicationEvent(ApplicationEvent e);
}
ApplicationEventMulticaster :事件广播接口
public interface ApplicationEventMulticaster extends ApplicationListener {
/**
* Add a listener to be notified of all events
* @param listener listener to add
*/
void addApplicationListener(ApplicationListener listener);
/**
* Remove a listener in the notification list]
* @param listener listener to remove
*/
void removeApplicationListener(ApplicationListener listener);
/**
* Remove all listeners registered with this multicaster.
* It will perform no action on event notification until more
* listeners are registered.
*/
void removeAllListeners();
}
ApplicationEventMulticasterImpl:事件广播实现类
public class ApplicationEventMulticasterImpl implements ApplicationEventMulticaster {
/** Set of listeners */
private Set eventListeners = new HashSet();
public void addApplicationListener(ApplicationListener l) {
eventListeners.add(l);
}
public void removeApplicationListener(ApplicationListener l) {
eventListeners.remove(l);
}
public void onApplicationEvent(ApplicationEvent e) {
Iterator i = eventListeners.iterator();
while (i.hasNext()) {
ApplicationListener l = (ApplicationListener) i.next();
l.onApplicationEvent(e);
}
}
public void removeAllListeners() {
eventListeners.clear();
}
}
那Listener是怎么加到广播里的呢?
refresh()方法里有个refreshListeners()方法
/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
private void refreshListeners() throws BeansException {
logger.info("Refreshing listeners");
Collection listeners = getBeansOfType(ApplicationListener.class, true, false).values();
logger.debug("Found " + listeners.size() + " listeners in bean factory");
for (Iterator it = listeners.iterator(); it.hasNext();) {
ApplicationListener listener = (ApplicationListener) it.next();
addListener(listener);
logger.info("Application listener [" + listener + "] added");
}
}
/**
* Subclasses can invoke this method to register a listener.
* Any beans in the context that are listeners are automatically added.
* @param listener the listener to register
*/
protected void addListener(ApplicationListener listener) {
this.eventMulticaster.addApplicationListener(listener);
}
好了,到现在我们也应该清楚事件机制的简单使用和怎么实现的了!