事件机制
相关概念:
事件EventObject
事件生成器 事件的产生者,生成事件后,使用事件发布器发布事件。
事件生成器工厂 生产多种类型的事件生成器
事件发布器EventPublisher 发布事件:将事件发布到广播器中。
事件广播器 通知在事件监听器注册表中注册的事件监听器。即将事件dispatch到对应的监听器上。
事件监听器EventListener 监听事件,并做相应的处理。
事件监听器注册表 管理事件监听器,广播器通过注册表来寻找指定的监听器。
执行流程:
1)初始化监听器注册表。
2)businessService ---> 生成事件 ---> 发布事件 ---> 广播器:从注册表中获取指定类型的监听器,并通知监听器 ---> 各个监听器响应该事件。
优点:
消除不同业务间的耦合关系。
jdk的事件机制:
事件:EventObject
未定义事件发布器
事件监听器:EventListener
spring的事件机制:
事件:ApplicationEvent
继承了jdk的EventObject
事件生成器:spring中并没有定义事件生成器,spring直接通过new ApplicationEvent的实现类来生成事件。
事件发布器:ApplicationEventPublisher
实现:
ApplicationContext继承了ApplicationEventPublisher,即ApplicationContext的实现类作为不同的事件发布器。
将事件发布到广播器中:AbstractApplicationContext调用广播器的multicastEvent()方法将事件发布到广播器中。
事件广播器:ApplicationEventMulticaster
实现:
默认广播器:SimpleApplicationEventMulticaster
使用multicastEvent()方法来广播事件:
从注册表中获取监听器:使用getApplicationListeners()方法从注册表中获取事件监听器。
通知监听器:使用invokeListener()方法来通知指定的监听器,invokeListener()方法内调用了监听器的onApplicationEvent方法。
事件监听器:ApplicationListener
继承了jdk的EventListener
事件监听器注册表:
实现:
数据结构:AbstractApplicationContext的applicationListeners属性:
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
注册监听器:通过AbstractApplicationContext的addApplicationListener()方法将监听器添加到注册表中。
初始化:容器启动的时候,会初始化注册表。
eg:在创建容器和初始化容器时会调用FrameworkServlet.configureAndRefreshWebApplicationContext()方法,该方法会调用addApplicationListener()方法来注册监听器。
注意:
广播器ApplicationEventMulticaster也维护了一份监听器的注册表。
在广播器初始化前,spring会向applicationListeners中注册监听器,
在广播器初始化后,spring会将applicationListeners中注册的监听器都添加到广播器自己维护的注册表中,并且,之后的监听器会直接注册到广播器自己的注册表中。
广播器在广播事件时,会通知自己维护的注册表中的监听器。
说明:
/**
* ApplicationContext(更确切的说是AbstractApplicationContext)在spring的事件机制中扮演了多个角色:事件发布器、事件广播器、监听器注册表
*/
public abstract class AbstractApplicationContext implements ApplicationContext {
// ApplicationContext继承了ApplicationEventPublisher,故AbstractApplicationContext即事件发布器
// 事件广播器
/** Helper class used in event publishing */
private ApplicationEventMulticaster applicationEventMulticaster;
// 事件监听器注册表
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();
/** ApplicationEvents published early */
private Set<ApplicationEvent> earlyApplicationEvents;
/** Parent context */
private ApplicationContext parent;
/**
* Load or refresh the persistent representation of the configuration,
* which might an XML file, properties file, or relational database schema.
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 这里将earlyApplicationEvents初始化为一个空集合
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context. 初始化广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them. 注册监听器
// 在监听器注册完成后,会使用广播器将earlyApplicationEvents中缓存的事件广播出去,并将earlyApplicationEvents置为null。
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
destroyBeans(); // Destroy already created singletons to avoid dangling resources.
cancelRefresh(ex); // Reset 'active' flag.
throw ex; // Propagate exception to caller.
} finally {
// Reset common introspection caches in Spring's core, since we might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
if (this.applicationEventMulticaster != null) {
this.applicationEventMulticaster.addApplicationListener(listener);
} else {
this.applicationListeners.add(listener);
}
}
// 发布事件
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
protected void publishEvent(Object event, ResolvableType eventType) {
// 如果事件的类型不是ApplicationEvent,则将事件包装为PayloadApplicationEvent事件。
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
} else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
// 若广播器还没有初始化,则先将事件缓存到earlyApplicationEvents中,
// 当 广播器初始化完成 且 监听器全部注册完成 后,spring会将earlyApplicationEvents中的事件广播出去,并将earlyApplicationEvents置为null
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
} else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
} else {
this.parent.publishEvent(event);
}
}
}
}
举例:
duboo服务的导出:
监听器:ServiceBean
ServiceBean实现了spring的ApplicationListener接口,并且监听着spring的上下文刷新事件(ContextRefreshedEvent),当监听到spring的上下文刷新事件时,执行服务导出操作。